import systemd-239-21.el8

This commit is contained in:
CentOS Sources 2020-01-21 18:33:31 -05:00 committed by Stepan Oksanichenko
parent 2aad85c23d
commit 22bbbfe74c
96 changed files with 10781 additions and 1 deletions

View File

@ -0,0 +1,87 @@
From 980418c331293aeb8595fcc95cbc4a9e1a485eda Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 25 Feb 2019 11:02:46 +0100
Subject: [PATCH] sd-bus: deal with cookie overruns
Apparently this happens IRL. Let's carefully deal with issues like this:
when we overrun, let's not go back to zero but instead leave the highest
cookie bit set. We use that as indication that we are in "overrun
territory", and then are particularly careful with checking cookies,
i.e. that they haven't been used for still outstanding replies yet. This
should retain the quick cookie generation behaviour we used to have, but
permits dealing with overruns.
Replaces: #11804
Fixes: #11809
(cherry picked from commit 1f82f5bb4237ed5f015daf93f818e9db95e764b8)
Resolves: #1694999
---
src/libsystemd/sd-bus/sd-bus.c | 47 +++++++++++++++++++++++++++++++++-
1 file changed, 46 insertions(+), 1 deletion(-)
diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c
index f53a98d6bf..3583e24e64 100644
--- a/src/libsystemd/sd-bus/sd-bus.c
+++ b/src/libsystemd/sd-bus/sd-bus.c
@@ -1597,6 +1597,47 @@ _public_ int sd_bus_get_bus_id(sd_bus *bus, sd_id128_t *id) {
return 0;
}
+#define COOKIE_CYCLED (UINT32_C(1) << 31)
+
+static uint64_t cookie_inc(uint64_t cookie) {
+
+ /* Stay within the 32bit range, since classic D-Bus can't deal with more */
+ if (cookie >= UINT32_MAX)
+ return COOKIE_CYCLED; /* Don't go back to zero, but use the highest bit for checking
+ * whether we are looping. */
+
+ return cookie + 1;
+}
+
+static int next_cookie(sd_bus *b) {
+ uint64_t new_cookie;
+
+ assert(b);
+
+ new_cookie = cookie_inc(b->cookie);
+
+ /* Small optimization: don't bother with checking for cookie reuse until we overran cookiespace at
+ * least once, but then do it thorougly. */
+ if (FLAGS_SET(new_cookie, COOKIE_CYCLED)) {
+ uint32_t i;
+
+ /* Check if the cookie is currently in use. If so, pick the next one */
+ for (i = 0; i < COOKIE_CYCLED; i++) {
+ if (!ordered_hashmap_contains(b->reply_callbacks, &new_cookie))
+ goto good;
+
+ new_cookie = cookie_inc(new_cookie);
+ }
+
+ /* Can't fulfill request */
+ return -EBUSY;
+ }
+
+good:
+ b->cookie = new_cookie;
+ return 0;
+}
+
static int bus_seal_message(sd_bus *b, sd_bus_message *m, usec_t timeout) {
int r;
@@ -1620,7 +1661,11 @@ static int bus_seal_message(sd_bus *b, sd_bus_message *m, usec_t timeout) {
return r;
}
- return sd_bus_message_seal(m, ++b->cookie, timeout);
+ r = next_cookie(b);
+ if (r < 0)
+ return r;
+
+ return sd_bus_message_seal(m, b->cookie, timeout);
}
static int bus_remarshal_message(sd_bus *b, sd_bus_message **m) {

View File

@ -0,0 +1,77 @@
From f551c05e4799386508e10f0f007251e426493a67 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Mon, 11 Mar 2019 12:27:18 +0900
Subject: [PATCH] journal-remote: do not request Content-Length if
Transfer-Encoding is chunked
This fixes a bug introduced by 7fdb237f5473cb8fc2129e57e8a0039526dcb4fd.
Closes #11571.
(cherry picked from commit a289dfd69b3ff4bccdde93e84b67c947bafa27e1)
Resolves: #1708849
---
src/journal-remote/journal-remote-main.c | 41 ++++++++++++++++--------
1 file changed, 27 insertions(+), 14 deletions(-)
diff --git a/src/journal-remote/journal-remote-main.c b/src/journal-remote/journal-remote-main.c
index 5b0bbba310..47fe9d7433 100644
--- a/src/journal-remote/journal-remote-main.c
+++ b/src/journal-remote/journal-remote-main.c
@@ -254,6 +254,7 @@ static int request_handler(
const char *header;
int r, code, fd;
_cleanup_free_ char *hostname = NULL;
+ bool chunked = false;
size_t len;
assert(connection);
@@ -279,21 +280,33 @@ static int request_handler(
return mhd_respond(connection, MHD_HTTP_UNSUPPORTED_MEDIA_TYPE,
"Content-Type: application/vnd.fdo.journal is required.");
+ header = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, "Transfer-Encoding");
+ if (header) {
+ if (!strcaseeq(header, "chunked"))
+ return mhd_respondf(connection, 0, MHD_HTTP_BAD_REQUEST,
+ "Unsupported Transfer-Encoding type: %s", header);
+
+ chunked = true;
+ }
+
header = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, "Content-Length");
- if (!header)
- return mhd_respond(connection, MHD_HTTP_LENGTH_REQUIRED,
- "Content-Length header is required.");
- r = safe_atozu(header, &len);
- if (r < 0)
- return mhd_respondf(connection, r, MHD_HTTP_LENGTH_REQUIRED,
- "Content-Length: %s cannot be parsed: %m", header);
-
- if (len > ENTRY_SIZE_MAX)
- /* When serialized, an entry of maximum size might be slightly larger,
- * so this does not correspond exactly to the limit in journald. Oh well.
- */
- return mhd_respondf(connection, 0, MHD_HTTP_PAYLOAD_TOO_LARGE,
- "Payload larger than maximum size of %u bytes", ENTRY_SIZE_MAX);
+ if (header) {
+ if (chunked)
+ return mhd_respond(connection, MHD_HTTP_BAD_REQUEST,
+ "Content-Length must not specified when Transfer-Encoding type is 'chuncked'");
+
+ r = safe_atozu(header, &len);
+ if (r < 0)
+ return mhd_respondf(connection, r, MHD_HTTP_LENGTH_REQUIRED,
+ "Content-Length: %s cannot be parsed: %m", header);
+
+ if (len > ENTRY_SIZE_MAX)
+ /* When serialized, an entry of maximum size might be slightly larger,
+ * so this does not correspond exactly to the limit in journald. Oh well.
+ */
+ return mhd_respondf(connection, 0, MHD_HTTP_PAYLOAD_TOO_LARGE,
+ "Payload larger than maximum size of %u bytes", ENTRY_SIZE_MAX);
+ }
{
const union MHD_ConnectionInfo *ci;

View File

@ -0,0 +1,79 @@
From fffbf1f90be5236b310bc0b10034815b1051f0ac Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Fri, 10 Aug 2018 11:07:54 +0900
Subject: [PATCH] journal: do not remove multiple spaces after identifier in
syslog message
Single space is used as separator.
C.f. discussions in #156.
Fixes #9839 introduced by a6aadf4ae0bae185dc4c414d492a4a781c80ffe5.
(cherry picked from commit 8595102d3ddde6d25c282f965573a6de34ab4421)
Resolves: #1691817
---
src/journal/journald-syslog.c | 4 +++-
src/journal/test-journal-syslog.c | 24 ++++++++++++++----------
2 files changed, 17 insertions(+), 11 deletions(-)
diff --git a/src/journal/journald-syslog.c b/src/journal/journald-syslog.c
index 97711ac7a3..e0b55cc566 100644
--- a/src/journal/journald-syslog.c
+++ b/src/journal/journald-syslog.c
@@ -219,7 +219,9 @@ size_t syslog_parse_identifier(const char **buf, char **identifier, char **pid)
if (t)
*identifier = t;
- e += strspn(p + e, WHITESPACE);
+ /* Single space is used as separator */
+ if (p[e] != '\0' && strchr(WHITESPACE, p[e]))
+ e++;
*buf = p + e;
return e;
diff --git a/src/journal/test-journal-syslog.c b/src/journal/test-journal-syslog.c
index 05f759817e..7294cde032 100644
--- a/src/journal/test-journal-syslog.c
+++ b/src/journal/test-journal-syslog.c
@@ -6,7 +6,7 @@
#include "string-util.h"
static void test_syslog_parse_identifier(const char *str,
- const char *ident, const char *pid, int ret) {
+ const char *ident, const char *pid, const char *rest, int ret) {
const char *buf = str;
_cleanup_free_ char *ident2 = NULL, *pid2 = NULL;
int ret2;
@@ -16,18 +16,22 @@ static void test_syslog_parse_identifier(const char *str,
assert_se(ret == ret2);
assert_se(ident == ident2 || streq_ptr(ident, ident2));
assert_se(pid == pid2 || streq_ptr(pid, pid2));
+ assert_se(streq(buf, rest));
}
int main(void) {
- test_syslog_parse_identifier("pidu[111]: xxx", "pidu", "111", 11);
- test_syslog_parse_identifier("pidu: xxx", "pidu", NULL, 6);
- test_syslog_parse_identifier("pidu: xxx", "pidu", NULL, 7);
- test_syslog_parse_identifier("pidu xxx", NULL, NULL, 0);
- test_syslog_parse_identifier(":", "", NULL, 1);
- test_syslog_parse_identifier(": ", "", NULL, 3);
- test_syslog_parse_identifier("pidu:", "pidu", NULL, 5);
- test_syslog_parse_identifier("pidu: ", "pidu", NULL, 6);
- test_syslog_parse_identifier("pidu : ", NULL, NULL, 0);
+ test_syslog_parse_identifier("pidu[111]: xxx", "pidu", "111", "xxx", 11);
+ test_syslog_parse_identifier("pidu: xxx", "pidu", NULL, "xxx", 6);
+ test_syslog_parse_identifier("pidu: xxx", "pidu", NULL, " xxx", 6);
+ test_syslog_parse_identifier("pidu xxx", NULL, NULL, "pidu xxx", 0);
+ test_syslog_parse_identifier(" pidu xxx", NULL, NULL, " pidu xxx", 0);
+ test_syslog_parse_identifier("", NULL, NULL, "", 0);
+ test_syslog_parse_identifier(" ", NULL, NULL, " ", 0);
+ test_syslog_parse_identifier(":", "", NULL, "", 1);
+ test_syslog_parse_identifier(": ", "", NULL, " ", 2);
+ test_syslog_parse_identifier("pidu:", "pidu", NULL, "", 5);
+ test_syslog_parse_identifier("pidu: ", "pidu", NULL, "", 6);
+ test_syslog_parse_identifier("pidu : ", NULL, NULL, "pidu : ", 0);
return 0;
}

View File

@ -0,0 +1,62 @@
From 4f9d00380ea41f5a4eb1610ae5c354a8f749cc98 Mon Sep 17 00:00:00 2001
From: Milan Broz <gmazyland@gmail.com>
Date: Mon, 27 May 2019 09:27:54 +0200
Subject: [PATCH] cryptsetup: Do not fallback to PLAIN mapping if LUKS data
device set fails.
If crypt_load() for LUKS succeeds, we know that it is a LUKS device.
Failure of data device setting should fail in this case; remapping
as a PLAIN device late could mean data corruption.
(If a user wants to map PLAIN device over a device with LUKS header,
it should be said explicitly with "plain" argument type.)
Also, if there is no explicit PLAIN type requested and crypt device
is already initialized (crypt_data_type() is set), do not run
the initialization again.
(cherry picked from commit 2e4beb875bcb24e7d7d4339cc202b0b3f2953f71)
Related: #1719153
---
src/cryptsetup/cryptsetup.c | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c
index abeba44ee8..5be1469d69 100644
--- a/src/cryptsetup/cryptsetup.c
+++ b/src/cryptsetup/cryptsetup.c
@@ -492,11 +492,14 @@ static int attach_luks_or_plain(struct crypt_device *cd,
return r;
}
- if (data_device)
+ if (data_device) {
r = crypt_set_data_device(cd, data_device);
+ if (r < 0)
+ return log_error_errno(r, "Failed to set LUKS data device %s: %m", data_device);
+ }
}
- if ((!arg_type && r < 0) || streq_ptr(arg_type, CRYPT_PLAIN)) {
+ if ((!arg_type && !crypt_get_type(cd)) || streq_ptr(arg_type, CRYPT_PLAIN)) {
struct crypt_params_plain params = {
.offset = arg_offset,
.skip = arg_skip,
@@ -543,14 +546,13 @@ static int attach_luks_or_plain(struct crypt_device *cd,
* parameters when used for plain
* mode. */
r = crypt_format(cd, CRYPT_PLAIN, cipher, cipher_mode, NULL, NULL, arg_keyfile_size, &params);
+ if (r < 0)
+ return log_error_errno(r, "Loading of cryptographic parameters failed: %m");
/* hash == NULL implies the user passed "plain" */
pass_volume_key = (params.hash == NULL);
}
- if (r < 0)
- return log_error_errno(r, "Loading of cryptographic parameters failed: %m");
-
log_info("Set cipher %s, mode %s, key size %i bits for device %s.",
crypt_get_cipher(cd),
crypt_get_cipher_mode(cd),

View File

@ -0,0 +1,79 @@
From 788fb775f7deb8c456868362454e2a5f50c6068f Mon Sep 17 00:00:00 2001
From: Milan Broz <gmazyland@gmail.com>
Date: Mon, 27 May 2019 09:43:03 +0200
Subject: [PATCH] cryptsetup: call crypt_load() for LUKS only once
The crypt_load() for LUKS2 can read a quite big area of disk
(metadata area size is configurable and can increase up to megabytes).
This initialization is not needed to be repeated, just use the existing context.
(This patch is also required for the following change.)
(cherry picked from commit ea9a9d49e4af31c49e5c216e7e5e2f533e727579)
Related: #1719153
---
src/cryptsetup/cryptsetup.c | 28 ++++++++++++----------------
1 file changed, 12 insertions(+), 16 deletions(-)
diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c
index 5be1469d69..a0bd80ea65 100644
--- a/src/cryptsetup/cryptsetup.c
+++ b/src/cryptsetup/cryptsetup.c
@@ -475,7 +475,6 @@ static int attach_tcrypt(
static int attach_luks_or_plain(struct crypt_device *cd,
const char *name,
const char *key_file,
- const char *data_device,
char **passwords,
uint32_t flags) {
int r = 0;
@@ -485,20 +484,6 @@ static int attach_luks_or_plain(struct crypt_device *cd,
assert(name);
assert(key_file || passwords);
- if (!arg_type || STR_IN_SET(arg_type, ANY_LUKS, CRYPT_LUKS1)) {
- r = crypt_load(cd, CRYPT_LUKS, NULL);
- if (r < 0) {
- log_error("crypt_load() failed on device %s.\n", crypt_get_device_name(cd));
- return r;
- }
-
- if (data_device) {
- r = crypt_set_data_device(cd, data_device);
- if (r < 0)
- return log_error_errno(r, "Failed to set LUKS data device %s: %m", data_device);
- }
- }
-
if ((!arg_type && !crypt_get_type(cd)) || streq_ptr(arg_type, CRYPT_PLAIN)) {
struct crypt_params_plain params = {
.offset = arg_offset,
@@ -687,6 +672,18 @@ int main(int argc, char *argv[]) {
log_warning("Key file %s is world-readable. This is not a good idea!", key_file);
}
+ if (!arg_type || STR_IN_SET(arg_type, ANY_LUKS, CRYPT_LUKS1)) {
+ r = crypt_load(cd, CRYPT_LUKS, NULL);
+ if (r < 0)
+ return log_error_errno(r, "Failed to load LUKS superblock on device %s: %m", crypt_get_device_name(cd));
+
+ if (arg_header) {
+ r = crypt_set_data_device(cd, argv[3]);
+ if (r < 0)
+ return log_error_errno(r, "Failed to set LUKS data device %s: %m", argv[3]);
+ }
+ }
+
for (tries = 0; arg_tries == 0 || tries < arg_tries; tries++) {
_cleanup_strv_free_erase_ char **passwords = NULL;
@@ -704,7 +701,6 @@ int main(int argc, char *argv[]) {
r = attach_luks_or_plain(cd,
argv[2],
key_file,
- arg_header ? argv[3] : NULL,
passwords,
flags);
if (r >= 0)

View File

@ -0,0 +1,45 @@
From 7a597a091de83a861d81166b0e863bf2977c829c Mon Sep 17 00:00:00 2001
From: Milan Broz <gmazyland@gmail.com>
Date: Mon, 27 May 2019 09:44:14 +0200
Subject: [PATCH] cryptsetup: Add LUKS2 token support.
LUKS2 supports so-called tokens. The libcryptsetup internally
support keyring token (it tries to open device using specified
keyring entry).
Only if all token fails (or are not available), it uses a passphrase.
This patch aligns the functionality with the cryptsetup utility
(cryptsetup luksOpen tries tokens first) but does not replace
the systemd native ask-password function (can be used the same in
combination with this patch).
(cherry picked from commit 894bb3ca4c730cc9e9d46ef5004ba4ca5e201d8d)
Resolves: #1719153
---
src/cryptsetup/cryptsetup.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c
index a0bd80ea65..4e1b3eff19 100644
--- a/src/cryptsetup/cryptsetup.c
+++ b/src/cryptsetup/cryptsetup.c
@@ -682,6 +682,18 @@ int main(int argc, char *argv[]) {
if (r < 0)
return log_error_errno(r, "Failed to set LUKS data device %s: %m", argv[3]);
}
+#ifdef CRYPT_ANY_TOKEN
+ /* Tokens are available in LUKS2 only, but it is ok to call (and fail) with LUKS1. */
+ if (!key_file) {
+ r = crypt_activate_by_token(cd, argv[2], CRYPT_ANY_TOKEN, NULL, flags);
+ if (r >= 0) {
+ log_debug("Volume %s activated with LUKS token id %i.", argv[2], r);
+ return 0;
+ }
+
+ log_debug_errno(r, "Token activation unsuccessful for device %s: %m", crypt_get_device_name(cd));
+ }
+#endif
}
for (tries = 0; arg_tries == 0 || tries < arg_tries; tries++) {

View File

@ -0,0 +1,30 @@
From 7b3ef169e3142fb471c48f265881b371380d77e0 Mon Sep 17 00:00:00 2001
From: Zhang Xianwei <zhang.xianwei8@zte.com.cn>
Date: Mon, 13 May 2019 18:41:55 +0800
Subject: [PATCH] udev/scsi_id: fix incorrect page length when get device
identification VPD page
The length of device identification VPD page is filled with two bytes,
but scsi_id only gets the low byte. Fix it.
Signed-off-by: Zhang Xianwei <zhang.xianwei8@zte.com.cn>
(cherry picked from commit 1f7b6872dbe8ccae1f3bda9aa6aeb87c9b42e01e)
Resolves: #1713227
---
src/udev/scsi_id/scsi_serial.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/udev/scsi_id/scsi_serial.c b/src/udev/scsi_id/scsi_serial.c
index fd91657a32..fb6055395d 100644
--- a/src/udev/scsi_id/scsi_serial.c
+++ b/src/udev/scsi_id/scsi_serial.c
@@ -661,7 +661,7 @@ static int do_scsi_page83_inquiry(struct udev *udev,
* Examine each descriptor returned. There is normally only
* one or a small number of descriptors.
*/
- for (j = 4; j <= (unsigned int)page_83[3] + 3; j += page_83[j + 3] + 4) {
+ for (j = 4; j <= ((unsigned)page_83[2] << 8) + (unsigned)page_83[3] + 3; j += page_83[j + 3] + 4) {
retval = check_fill_0x83_id(udev,
dev_scsi, &page_83[j],
&id_search_list[id_ind],

View File

@ -0,0 +1,55 @@
From d70e1c2eb596b8144197192e2324abbb45f547a6 Mon Sep 17 00:00:00 2001
From: Jonathon Kowalski <bl0pbl33p@gmail.com>
Date: Thu, 17 Jan 2019 17:08:00 +0000
Subject: [PATCH] Change job mode of manager triggered restarts to JOB_REPLACE
Fixes: #11305
Fixes: #3260
Related: #11456
So, here's what happens in the described scenario in #11305. A unit goes
down, and that triggeres stop jobs for the other two units as they were
bound to it. Now, the timer for manager triggered restarts kicks in and
schedules a restart job with the JOB_FAIL job mode. This means there is
a stop job installed on those units, and now due to them being bound to
us they also get a restart job enqueued. This however is a conflicts, as
neither stop can merge into restart, nor restart into stop. However,
restart should be able to replace stop in any case. If the stop
procedure is ongoing, it can cancel the stop job, install itself, and
then after reaching dead finish and convert itself to a start job.
However, if we increase the timer, then it can always take those units
from inactive -> auto-restart.
We change the job mode to JOB_REPLACE so the restart job cancels the
stop job and installs itself.
Also, the original bug could be worked around by bumping RestartSec= to
avoid the conflicting.
This doesn't seem to be something that is going to break uses. That is
because for those who already had it working, there must have never been
conflicting jobs, as that would result in a desctructive transaction by
virtue of the job mode used.
After this change, the test case is able to work nicely without issues.
(cherry picked from commit 03ff2dc71ecb09272d728d458498b44f7f132f51)
Resolves: #1712524
---
src/core/service.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/core/service.c b/src/core/service.c
index 3eab749362..8342c131c8 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -2133,7 +2133,7 @@ static void service_enter_restart(Service *s) {
* restarted. We use JOB_RESTART (instead of the more obvious
* JOB_START) here so that those dependency jobs will be added
* as well. */
- r = manager_add_job(UNIT(s)->manager, JOB_RESTART, UNIT(s), JOB_FAIL, &error, NULL);
+ r = manager_add_job(UNIT(s)->manager, JOB_RESTART, UNIT(s), JOB_REPLACE, &error, NULL);
if (r < 0)
goto fail;

View File

@ -0,0 +1,58 @@
From 8d1a8f099dbf79d0e18e055721228192a637a759 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Thu, 6 Dec 2018 18:51:56 +0100
Subject: [PATCH] bash-completion: analyze: support 'security'
(cherry picked from commit 83da42c3bf86e8787cfec2c7fb6ca379dfec3632)
Resolves: #1733395
---
shell-completion/bash/systemd-analyze | 20 +++++++++++++++++++-
1 file changed, 19 insertions(+), 1 deletion(-)
diff --git a/shell-completion/bash/systemd-analyze b/shell-completion/bash/systemd-analyze
index 21d0fcf1b8..b4fcfc6492 100644
--- a/shell-completion/bash/systemd-analyze
+++ b/shell-completion/bash/systemd-analyze
@@ -31,8 +31,13 @@ __get_machines() {
machinectl list --no-legend --no-pager | { while read a b; do echo " $a"; done; };
}
+__get_services() {
+ systemctl list-units --no-legend --no-pager -t service --all $1 | \
+ { while read -r a b c; do [[ $b == "loaded" ]]; echo " $a"; done }
+}
+
_systemd_analyze() {
- local i verb comps
+ local i verb comps mode
local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]}
local -A OPTS=(
@@ -51,6 +56,7 @@ _systemd_analyze() {
[SECCOMP_FILTER]='syscall-filter'
[SERVICE_WATCHDOGS]='service-watchdogs'
[CAT_CONFIG]='cat-config'
+ [SECURITY]='security'
)
local CONFIGS='systemd/bootchart.conf systemd/coredump.conf systemd/journald.conf
@@ -149,6 +155,18 @@ _systemd_analyze() {
comps="$CONFIGS $( compgen -A file -- "$cur" )"
compopt -o filenames
fi
+
+ elif __contains_word "$verb" ${VERBS[SECURITY]}; then
+ if [[ $cur = -* ]]; then
+ comps='--help --version --no-pager --system --user -H --host -M --machine'
+ else
+ if __contains_word "--user" ${COMP_WORDS[*]}; then
+ mode=--user
+ else
+ mode=--system
+ fi
+ comps=$( __get_services $mode )
+ fi
fi
COMPREPLY=( $(compgen -W '$comps' -- "$cur") )

View File

@ -0,0 +1,28 @@
From 705a67a53a8a1b836ef17f048366bbf33357afc1 Mon Sep 17 00:00:00 2001
From: Jan Synacek <jsynacek@redhat.com>
Date: Tue, 14 May 2019 10:45:08 +0200
Subject: [PATCH] man: note that journal does not validate syslog fields
(cherry picked from commit 63ea8032f28052f7cda860e5324c0a83dee7ed23)
Resolves: #1707175
---
man/systemd.journal-fields.xml | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/man/systemd.journal-fields.xml b/man/systemd.journal-fields.xml
index c079274c32..0c95c4cd95 100644
--- a/man/systemd.journal-fields.xml
+++ b/man/systemd.journal-fields.xml
@@ -111,6 +111,11 @@
<varname>program_invocation_short_name</varname> variable,
see
<citerefentry project='die-net'><refentrytitle>program_invocation_short_name</refentrytitle><manvolnum>3</manvolnum></citerefentry>.)</para>
+ <para>Note that the journal service does not validate the values of any structured
+ journal fields whose name is not prefixed with an underscore, and this includes any
+ syslog related fields such as these. Hence, applications that supply a facility, PID,
+ or log level are expected to do so properly formatted, i.e. as numeric integers formatted
+ as decimal strings.</para>
</listitem>
</varlistentry>

View File

@ -0,0 +1,22 @@
From 72dd8d8cd1a7417805009050f859d502b1c6cf3e Mon Sep 17 00:00:00 2001
From: Jan Synacek <jsynacek@redhat.com>
Date: Thu, 6 Jun 2019 09:35:27 +0200
Subject: [PATCH] rules: skip memory hotplug on ppc64
Resolves (#1713159)
---
rules/40-redhat.rules | 1 +
1 file changed, 1 insertion(+)
diff --git a/rules/40-redhat.rules b/rules/40-redhat.rules
index 17b33682bd..fadc6e59f1 100644
--- a/rules/40-redhat.rules
+++ b/rules/40-redhat.rules
@@ -7,6 +7,7 @@ SUBSYSTEM=="cpu", ACTION=="add", TEST=="online", ATTR{online}=="0", ATTR{online}
SUBSYSTEM!="memory", GOTO="memory_hotplug_end"
ACTION!="add", GOTO="memory_hotplug_end"
PROGRAM="/bin/uname -p", RESULT=="s390*", GOTO="memory_hotplug_end"
+PROGRAM="/bin/uname -p", RESULT=="ppc64*", GOTO="memory_hotplug_end"
ENV{.state}="online"
PROGRAM="/bin/systemd-detect-virt", RESULT=="none", ENV{.state}="online_movable"

View File

@ -0,0 +1,86 @@
From daf63a3c6c6cd241017bdf9a26c7b1caf744e69b Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Wed, 17 Jul 2019 14:53:07 +0200
Subject: [PATCH] mount: simplify /proc/self/mountinfo handler
Our IO handler is only installed for one fd, hence there's no reason to
conditionalize on it again.
Also, split out the draining into a helper function of its own.
(cherry picked from commit fcd8e119c28be19ffbc5227089cf4d3b8ba60238)
Conflicts:
src/core/mount.c
Related: #1696178
---
src/core/mount.c | 48 ++++++++++++++++++++++++++----------------------
1 file changed, 26 insertions(+), 22 deletions(-)
diff --git a/src/core/mount.c b/src/core/mount.c
index 16229d4af1..85b07375e2 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -1758,6 +1758,29 @@ fail:
mount_shutdown(m);
}
+static int drain_libmount(Manager *m) {
+ bool rescan = false;
+ int r;
+
+ assert(m);
+
+ /* Drain all events and verify that the event is valid.
+ *
+ * Note that libmount also monitors /run/mount mkdir if the directory does not exist yet. The mkdir
+ * may generate event which is irrelevant for us.
+ *
+ * error: r < 0; valid: r == 0, false positive: r == 1 */
+ do {
+ r = mnt_monitor_next_change(m->mount_monitor, NULL, NULL);
+ if (r < 0)
+ return log_error_errno(r, "Failed to drain libmount events: %m");
+ if (r == 0)
+ rescan = true;
+ } while (r == 0);
+
+ return rescan;
+}
+
static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
_cleanup_set_free_ Set *around = NULL, *gone = NULL;
Manager *m = userdata;
@@ -1769,28 +1792,9 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
assert(m);
assert(revents & EPOLLIN);
- if (fd == mnt_monitor_get_fd(m->mount_monitor)) {
- bool rescan = false;
-
- /* Drain all events and verify that the event is valid.
- *
- * Note that libmount also monitors /run/mount mkdir if the
- * directory does not exist yet. The mkdir may generate event
- * which is irrelevant for us.
- *
- * error: r < 0; valid: r == 0, false positive: rc == 1 */
- do {
- r = mnt_monitor_next_change(m->mount_monitor, NULL, NULL);
- if (r == 0)
- rescan = true;
- else if (r < 0)
- return log_error_errno(r, "Failed to drain libmount events");
- } while (r == 0);
-
- log_debug("libmount event [rescan: %s]", yes_no(rescan));
- if (!rescan)
- return 0;
- }
+ r = drain_libmount(m);
+ if (r <= 0)
+ return r;
r = mount_load_proc_self_mountinfo(m, true);
if (r < 0) {

View File

@ -0,0 +1,90 @@
From 4bc21bbc61acd1ce114da381a9742f6bcd4ffde8 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Wed, 17 Jul 2019 18:57:13 +0200
Subject: [PATCH] mount: rescan /proc/self/mountinfo before processing waitid()
results
(The interesting bits about the what and why are in a comment in the
patch, please have a look there instead of looking here in the commit
msg).
Fixes: #10872
(cherry picked from commit 350804867dbcc9b7ccabae1187d730d37e2d8a21)
Conflicts:
src/core/mount.c
Resolves: #1696178
---
src/core/mount.c | 30 +++++++++++++++++++++++++++---
1 file changed, 27 insertions(+), 3 deletions(-)
diff --git a/src/core/mount.c b/src/core/mount.c
index 85b07375e2..2ac04e3874 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -53,6 +53,7 @@ static const UnitActiveState state_translation_table[_MOUNT_STATE_MAX] = {
static int mount_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata);
static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata);
+static int mount_process_proc_self_mountinfo(Manager *m);
static bool MOUNT_STATE_WITH_PROCESS(MountState state) {
return IN_SET(state,
@@ -1241,6 +1242,22 @@ static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) {
if (pid != m->control_pid)
return;
+ /* So here's the thing, we really want to know before /usr/bin/mount or /usr/bin/umount exit whether
+ * they established/remove a mount. This is important when mounting, but even more so when unmounting
+ * since we need to deal with nested mounts and otherwise cannot safely determine whether to repeat
+ * the unmounts. In theory, the kernel fires /proc/self/mountinfo changes off before returning from
+ * the mount() or umount() syscalls, and thus we should see the changes to the proc file before we
+ * process the waitid() for the /usr/bin/(u)mount processes. However, this is unfortunately racy: we
+ * have to waitid() for processes using P_ALL (since we need to reap unexpected children that got
+ * reparented to PID 1), but when using P_ALL we might end up reaping processes that terminated just
+ * instants ago, i.e. already after our last event loop iteration (i.e. after the last point we might
+ * have noticed /proc/self/mountinfo events via epoll). This means event loop priorities for
+ * processing SIGCHLD vs. /proc/self/mountinfo IO events are not as relevant as we want. To fix that
+ * race, let's explicitly scan /proc/self/mountinfo before we start processing /usr/bin/(u)mount
+ * dying. It's ugly, but it makes our ordering systematic again, and makes sure we always see
+ * /proc/self/mountinfo changes before our mount/umount exits. */
+ (void) mount_process_proc_self_mountinfo(u->manager);
+
m->control_pid = 0;
if (is_clean_exit(code, status, EXIT_CLEAN_COMMAND, NULL))
@@ -1781,16 +1798,14 @@ static int drain_libmount(Manager *m) {
return rescan;
}
-static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
+static int mount_process_proc_self_mountinfo(Manager *m) {
_cleanup_set_free_ Set *around = NULL, *gone = NULL;
- Manager *m = userdata;
const char *what;
Iterator i;
Unit *u;
int r;
assert(m);
- assert(revents & EPOLLIN);
r = drain_libmount(m);
if (r <= 0)
@@ -1898,6 +1913,15 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
return 0;
}
+static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
+ Manager *m = userdata;
+
+ assert(m);
+ assert(revents & EPOLLIN);
+
+ return mount_process_proc_self_mountinfo(m);
+}
+
static void mount_reset_failed(Unit *u) {
Mount *m = MOUNT(u);

View File

@ -0,0 +1,69 @@
From a0c135f7771dbe3a6cd3da2aaa106900be0f4470 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Wed, 17 Jul 2019 18:58:44 +0200
Subject: [PATCH] swap: scan /proc/swaps before processing waitid() results
Similar to the previous commit, but for /proc/swaps, where the same
logic and rationale applies.
(cherry picked from commit bcce581d65de68cca01c73e1c890e261e72d20af)
Related: #1696178
---
src/core/swap.c | 18 +++++++++++++++---
1 file changed, 15 insertions(+), 3 deletions(-)
diff --git a/src/core/swap.c b/src/core/swap.c
index e01e61e56d..b644753a1c 100644
--- a/src/core/swap.c
+++ b/src/core/swap.c
@@ -40,6 +40,7 @@ static const UnitActiveState state_translation_table[_SWAP_STATE_MAX] = {
static int swap_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata);
static int swap_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata);
+static int swap_process_proc_swaps(Manager *m);
static bool SWAP_STATE_WITH_PROCESS(SwapState state) {
return IN_SET(state,
@@ -990,6 +991,10 @@ static void swap_sigchld_event(Unit *u, pid_t pid, int code, int status) {
if (pid != s->control_pid)
return;
+ /* Let's scan /proc/swaps before we process SIGCHLD. For the reasoning see the similar code in
+ * mount.c */
+ (void) swap_process_proc_swaps(u->manager);
+
s->control_pid = 0;
if (is_clean_exit(code, status, EXIT_CLEAN_COMMAND, NULL))
@@ -1125,13 +1130,11 @@ static int swap_load_proc_swaps(Manager *m, bool set_flags) {
return r;
}
-static int swap_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
- Manager *m = userdata;
+static int swap_process_proc_swaps(Manager *m) {
Unit *u;
int r;
assert(m);
- assert(revents & EPOLLPRI);
r = swap_load_proc_swaps(m, true);
if (r < 0) {
@@ -1205,6 +1208,15 @@ static int swap_dispatch_io(sd_event_source *source, int fd, uint32_t revents, v
return 1;
}
+static int swap_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
+ Manager *m = userdata;
+
+ assert(m);
+ assert(revents & EPOLLPRI);
+
+ return swap_process_proc_swaps(m);
+}
+
static Unit *swap_following(Unit *u) {
Swap *s = SWAP(u);
Swap *other, *first = NULL;

View File

@ -0,0 +1,25 @@
From ebe93460ef5ae3744c4b627361f4dc5815cffc13 Mon Sep 17 00:00:00 2001
From: Jan Synacek <jsynacek@redhat.com>
Date: Wed, 31 Jul 2019 09:13:41 +0200
Subject: [PATCH] analyze-security: fix potential division by zero
Upstream PR: https://github.com/systemd/systemd/pull/13238
Resolves: #1734400
---
src/analyze/analyze-security.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/analyze/analyze-security.c b/src/analyze/analyze-security.c
index 541fc0d97a..eec040d5c3 100644
--- a/src/analyze/analyze-security.c
+++ b/src/analyze/analyze-security.c
@@ -1494,6 +1494,8 @@ static int assess(const struct security_info *info, Table *overview_table, Analy
}
}
+ assert(weight_sum > 0);
+
if (details_table) {
size_t row;

View File

@ -0,0 +1,26 @@
From cffe5d0e781f6fa7f2275b94d2dcc26e00859a78 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Wed, 17 Jul 2019 19:16:33 +0200
Subject: [PATCH] core: never propagate reload failure to service result
Fixes: #11238
(cherry picked from commit d611cfa748aaf600832160132774074e808c82c7)
Resolves: #1735787
---
src/core/service.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/core/service.c b/src/core/service.c
index 8342c131c8..24f167572a 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -3310,7 +3310,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
"Control process exited, code=%s status=%i",
sigchld_code_to_string(code), status);
- if (s->result == SERVICE_SUCCESS)
+ if (s->state != SERVICE_RELOAD && s->result == SERVICE_SUCCESS)
s->result = f;
if (s->control_command &&

View File

@ -0,0 +1,59 @@
From d11fdacaf3c804b60dfe8371062f34ac2b624ac9 Mon Sep 17 00:00:00 2001
From: Jan Synacek <jsynacek@redhat.com>
Date: Fri, 13 Sep 2019 09:23:32 +0200
Subject: [PATCH] man: document systemd-analyze security
(cherry-picked from commit ee93c1e664a7bbc59f1578e285c871999507b14d)
Resolves: #1750343
---
man/systemd-analyze.xml | 29 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/man/systemd-analyze.xml b/man/systemd-analyze.xml
index 7aa10fc68e..f3b595880f 100644
--- a/man/systemd-analyze.xml
+++ b/man/systemd-analyze.xml
@@ -106,6 +106,12 @@
<arg choice="plain">service-watchdogs</arg>
<arg choice="opt"><replaceable>BOOL</replaceable></arg>
</cmdsynopsis>
+ <cmdsynopsis>
+ <command>systemd-analyze</command>
+ <arg choice="opt" rep="repeat">OPTIONS</arg>
+ <arg choice="plain">security</arg>
+ <arg choice="plain" rep="repeat"><replaceable>UNIT</replaceable></arg>
+ </cmdsynopsis>
</refsynopsisdiv>
<refsect1>
@@ -253,6 +259,29 @@ NAutoVTs=8
<citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
The hardware watchdog is not affected by this setting.</para>
+ <para><command>systemd-analyze security</command> analyzes the security and sandboxing settings of one or more
+ specified service units. If at least one unit name is specified the security settings of the specified service
+ units are inspected and a detailed analysis is shown. If no unit name is specified, all currently loaded,
+ long-running service units are inspected and a terse table with results shown. The command checks for various
+ security-related service settings, assigning each a numeric "exposure level" value, depending on how important a
+ setting is. It then calculates an overall exposure level for the whole unit, which is an estimation in the range
+ 0.0…10.0 indicating how exposed a service is security-wise. High exposure levels indicate very little applied
+ sandboxing. Low exposure levels indicate tight sandboxing and strongest security restrictions. Note that this only
+ analyzes the per-service security features systemd itself implements. This means that any additional security
+ mechanisms applied by the service code itself are not accounted for. The exposure level determined this way should
+ not be misunderstood: a high exposure level neither means that there is no effective sandboxing applied by the
+ service code itself, nor that the service is actually vulnerable to remote or local attacks. High exposure levels
+ do indicate however that most likely the service might benefit from additional settings applied to them. Please
+ note that many of the security and sandboxing settings individually can be circumvented — unless combined with
+ others. For example, if a service retains the privilege to establish or undo mount points many of the sandboxing
+ options can be undone by the service code itself. Due to that is essential that each service uses the most
+ comprehensive and strict sandboxing and security settings possible. The tool will take into account some of these
+ combinations and relationships between the settings, but not all. Also note that the security and sandboxing
+ settings analyzed here only apply to the operations executed by the service code itself. If a service has access to
+ an IPC system (such as D-Bus) it might request operations from other services that are not subject to the same
+ restrictions. Any comprehensive security and sandboxing analysis is hence incomplete if the IPC access policy is
+ not validated too.</para>
+
<para>If no command is passed, <command>systemd-analyze
time</command> is implied.</para>

View File

@ -0,0 +1,772 @@
From a2e00522971897909db2a81b4daf10e5700f453e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Fri, 15 Mar 2019 10:13:55 +0100
Subject: [PATCH] man: reorder and add examples to systemd-analyze(1)
The number of verbs supported by systemd-analyze has grown quite a bit, and the
man page has become an unreadable wall of text. Let's put each verb in a
separate subsection, grouping similar verbs together, and add a lot of examples
to guide the user.
(cherry picked from commit d323a99001c1f7625e8ac902e18deb514a4ca18d)
Related: #1750343
---
man/systemd-analyze.xml | 678 +++++++++++++++++++++++++---------------
1 file changed, 429 insertions(+), 249 deletions(-)
diff --git a/man/systemd-analyze.xml b/man/systemd-analyze.xml
index f3b595880f..7c873cbdd1 100644
--- a/man/systemd-analyze.xml
+++ b/man/systemd-analyze.xml
@@ -41,46 +41,50 @@
<arg choice="plain">critical-chain</arg>
<arg choice="opt" rep="repeat"><replaceable>UNIT</replaceable></arg>
</cmdsynopsis>
+
<cmdsynopsis>
<command>systemd-analyze</command>
<arg choice="opt" rep="repeat">OPTIONS</arg>
- <arg choice="plain">plot</arg>
- <arg choice="opt">&gt; file.svg</arg>
+ <arg choice="plain">log-level</arg>
+ <arg choice="opt"><replaceable>LEVEL</replaceable></arg>
</cmdsynopsis>
<cmdsynopsis>
<command>systemd-analyze</command>
<arg choice="opt" rep="repeat">OPTIONS</arg>
- <arg choice="plain">dot</arg>
- <arg choice="opt" rep="repeat"><replaceable>PATTERN</replaceable></arg>
- <arg choice="opt">&gt; file.dot</arg>
+ <arg choice="plain">log-target</arg>
+ <arg choice="opt"><replaceable>TARGET</replaceable></arg>
</cmdsynopsis>
<cmdsynopsis>
<command>systemd-analyze</command>
<arg choice="opt" rep="repeat">OPTIONS</arg>
- <arg choice="plain">dump</arg>
+ <arg choice="plain">service-watchdogs</arg>
+ <arg choice="opt"><replaceable>BOOL</replaceable></arg>
</cmdsynopsis>
+
<cmdsynopsis>
<command>systemd-analyze</command>
<arg choice="opt" rep="repeat">OPTIONS</arg>
- <arg choice="plain">cat-config</arg>
- <arg choice="plain" rep="repeat"><replaceable>NAME</replaceable>|<replaceable>PATH</replaceable></arg>
+ <arg choice="plain">dump</arg>
</cmdsynopsis>
+
<cmdsynopsis>
<command>systemd-analyze</command>
<arg choice="opt" rep="repeat">OPTIONS</arg>
- <arg choice="plain">unit-paths</arg>
+ <arg choice="plain">plot</arg>
+ <arg choice="opt">>file.svg</arg>
</cmdsynopsis>
<cmdsynopsis>
<command>systemd-analyze</command>
<arg choice="opt" rep="repeat">OPTIONS</arg>
- <arg choice="plain">log-level</arg>
- <arg choice="opt"><replaceable>LEVEL</replaceable></arg>
+ <arg choice="plain">dot</arg>
+ <arg choice="opt" rep="repeat"><replaceable>PATTERN</replaceable></arg>
+ <arg choice="opt">>file.dot</arg>
</cmdsynopsis>
+
<cmdsynopsis>
<command>systemd-analyze</command>
<arg choice="opt" rep="repeat">OPTIONS</arg>
- <arg choice="plain">log-target</arg>
- <arg choice="opt"><replaceable>TARGET</replaceable></arg>
+ <arg choice="plain">unit-paths</arg>
</cmdsynopsis>
<cmdsynopsis>
<command>systemd-analyze</command>
@@ -91,20 +95,20 @@
<cmdsynopsis>
<command>systemd-analyze</command>
<arg choice="opt" rep="repeat">OPTIONS</arg>
- <arg choice="plain">verify</arg>
- <arg choice="opt" rep="repeat"><replaceable>FILES</replaceable></arg>
+ <arg choice="plain">calendar</arg>
+ <arg choice="plain" rep="repeat"><replaceable>SPECS</replaceable></arg>
</cmdsynopsis>
<cmdsynopsis>
<command>systemd-analyze</command>
<arg choice="opt" rep="repeat">OPTIONS</arg>
- <arg choice="plain">calendar</arg>
- <arg choice="plain" rep="repeat"><replaceable>SPECS</replaceable></arg>
+ <arg choice="plain">timespan</arg>
+ <arg choice="plain" rep="repeat"><replaceable>SPAN</replaceable></arg>
</cmdsynopsis>
<cmdsynopsis>
<command>systemd-analyze</command>
<arg choice="opt" rep="repeat">OPTIONS</arg>
- <arg choice="plain">service-watchdogs</arg>
- <arg choice="opt"><replaceable>BOOL</replaceable></arg>
+ <arg choice="plain">cat-config</arg>
+ <arg choice="plain" rep="repeat"><replaceable>NAME</replaceable>|<replaceable>PATH</replaceable></arg>
</cmdsynopsis>
<cmdsynopsis>
<command>systemd-analyze</command>
@@ -123,73 +127,299 @@
verify the correctness of unit files. It is also used to access
special functions useful for advanced system manager debugging.</para>
- <para><command>systemd-analyze time</command> prints the time
- spent in the kernel before userspace has been reached, the time
- spent in the initial RAM disk (initrd) before normal system
- userspace has been reached, and the time normal system userspace
- took to initialize. Note that these measurements simply measure
- the time passed up to the point where all system services have
- been spawned, but not necessarily until they fully finished
- initialization or the disk is idle.</para>
-
- <para><command>systemd-analyze blame</command> prints a list of
- all running units, ordered by the time they took to initialize.
- This information may be used to optimize boot-up times. Note that
- the output might be misleading as the initialization of one
- service might be slow simply because it waits for the
- initialization of another service to complete.
- Also note: <command>systemd-analyze blame</command> doesn't display
- results for services with <varname>Type=simple</varname>,
- because systemd considers such services to be started immediately,
- hence no measurement of the initialization delays can be done.</para>
-
- <para><command>systemd-analyze critical-chain
- [<replaceable>UNIT…</replaceable>]</command> prints a tree of
- the time-critical chain of units (for each of the specified
- <replaceable>UNIT</replaceable>s or for the default target
- otherwise). The time after the unit is active or started is
- printed after the "@" character. The time the unit takes to start
- is printed after the "+" character. Note that the output might be
- misleading as the initialization of one service might depend on
- socket activation and because of the parallel execution of
- units.</para>
-
- <para><command>systemd-analyze plot</command> prints an SVG
- graphic detailing which system services have been started at what
- time, highlighting the time they spent on initialization.</para>
-
- <para><command>systemd-analyze dot</command> generates textual
- dependency graph description in dot format for further processing
- with the GraphViz
- <citerefentry project='die-net'><refentrytitle>dot</refentrytitle><manvolnum>1</manvolnum></citerefentry>
- tool. Use a command line like <command>systemd-analyze dot | dot
- -Tsvg > systemd.svg</command> to generate a graphical dependency
- tree. Unless <option>--order</option> or
- <option>--require</option> is passed, the generated graph will
- show both ordering and requirement dependencies. Optional pattern
- globbing style specifications (e.g. <filename>*.target</filename>)
- may be given at the end. A unit dependency is included in the
- graph if any of these patterns match either the origin or
- destination node.</para>
-
- <para><command>systemd-analyze dump</command> outputs a (usually
- very long) human-readable serialization of the complete server
- state. Its format is subject to change without notice and should
- not be parsed by applications.</para>
-
- <para><command>systemd-analyze cat-config</command> is similar
- to <command>systemctl cat</command>, but operates on config files.
- It will copy the contents of a config file and any drop-ins to standard
- output, using the usual systemd set of directories and rules for
- precedence. Each argument must be either an absolute path including
- the prefix (such as <filename>/etc/systemd/logind.conf</filename> or
- <filename>/usr/lib/systemd/logind.conf</filename>), or a name
- relative to the prefix (such as <filename>systemd/logind.conf</filename>).
- </para>
+ <para>If no command is passed, <command>systemd-analyze
+ time</command> is implied.</para>
+
+ <refsect2>
+ <title><command>systemd-analyze time</command></title>
+
+ <para>This command prints the time spent in the kernel before userspace has been reached, the time
+ spent in the initial RAM disk (initrd) before normal system userspace has been reached, and the time
+ normal system userspace took to initialize. Note that these measurements simply measure the time passed
+ up to the point where all system services have been spawned, but not necessarily until they fully
+ finished initialization or the disk is idle.</para>
+
+ <example>
+ <title><command>Show how long the boot took</command></title>
+
+ <programlisting># in a container
+$ systemd-analyze time
+Startup finished in 296ms (userspace)
+multi-user.target reached after 275ms in userspace
+
+# on a real machine
+$ systemd-analyze time
+Startup finished in 2.584s (kernel) + 19.176s (initrd) + 47.847s (userspace) = 1min 9.608s
+multi-user.target reached after 47.820s in userspace
+</programlisting>
+ </example>
+ </refsect2>
+
+ <refsect2>
+ <title><command>systemd-analyze blame</command></title>
+
+ <para>This command prints a list of all running units, ordered by the time they took to initialize.
+ This information may be used to optimize boot-up times. Note that the output might be misleading as the
+ initialization of one service might be slow simply because it waits for the initialization of another
+ service to complete. Also note: <command>systemd-analyze blame</command> doesn't display results for
+ services with <varname>Type=simple</varname>, because systemd considers such services to be started
+ immediately, hence no measurement of the initialization delays can be done.</para>
+
+ <example>
+ <title><command>Show which units took the most time during boot</command></title>
+
+ <programlisting>$ systemd-analyze blame
+ 32.875s pmlogger.service
+ 20.905s systemd-networkd-wait-online.service
+ 13.299s dev-vda1.device
+ ...
+ 23ms sysroot.mount
+ 11ms initrd-udevadm-cleanup-db.service
+ 3ms sys-kernel-config.mount
+ </programlisting>
+ </example>
+ </refsect2>
+
+ <refsect2>
+ <title><command>systemd-analyze critical-chain <optional><replaceable>UNIT</replaceable>...</optional></command></title>
+
+ <para>This command prints a tree of the time-critical chain of units (for each of the specified
+ <replaceable>UNIT</replaceable>s or for the default target otherwise). The time after the unit is
+ active or started is printed after the "@" character. The time the unit takes to start is printed after
+ the "+" character. Note that the output might be misleading as the initialization of services might
+ depend on socket activation and because of the parallel execution of units.</para>
+
+ <example>
+ <title><command>systemd-analyze time</command></title>
+
+ <programlisting>$ systemd-analyze critical-chain
+multi-user.target @47.820s
+└─pmie.service @35.968s +548ms
+ └─pmcd.service @33.715s +2.247s
+ └─network-online.target @33.712s
+ └─systemd-networkd-wait-online.service @12.804s +20.905s
+ └─systemd-networkd.service @11.109s +1.690s
+ └─systemd-udevd.service @9.201s +1.904s
+ └─systemd-tmpfiles-setup-dev.service @7.306s +1.776s
+ └─kmod-static-nodes.service @6.976s +177ms
+ └─systemd-journald.socket
+ └─system.slice
+ └─-.slice
+</programlisting>
+ </example>
+ </refsect2>
+
+ <refsect2>
+ <title><command>systemd-analyze log-level [<replaceable>LEVEL</replaceable>]</command></title>
+
+ <para><command>systemd-analyze log-level</command> prints the current log level of the
+ <command>systemd</command> daemon. If an optional argument <replaceable>LEVEL</replaceable> is
+ provided, then the command changes the current log level of the <command>systemd</command> daemon to
+ <replaceable>LEVEL</replaceable> (accepts the same values as <option>--log-level=</option> described in
+ <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>).</para>
+ </refsect2>
+
+ <refsect2>
+ <title><command>systemd-analyze log-target [<replaceable>TARGET</replaceable>]</command></title>
+
+ <para><command>systemd-analyze log-target</command> prints the current log target of the
+ <command>systemd</command> daemon. If an optional argument <replaceable>TARGET</replaceable> is
+ provided, then the command changes the current log target of the <command>systemd</command> daemon to
+ <replaceable>TARGET</replaceable> (accepts the same values as <option>--log-target=</option>, described
+ in <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>).</para>
+ </refsect2>
+
+ <refsect2>
+ <title><command>systemd-analyze service-watchdogs [yes|no]</command></title>
+
+ <para><command>systemd-analyze service-watchdogs</command> prints the current state of service runtime
+ watchdogs of the <command>systemd</command> daemon. If an optional boolean argument is provided, then
+ globally enables or disables the service runtime watchdogs (<option>WatchdogSec=</option>) and
+ emergency actions (e.g. <option>OnFailure=</option> or <option>StartLimitAction=</option>); see
+ <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+ The hardware watchdog is not affected by this setting.</para>
+ </refsect2>
+
+ <refsect2>
+ <title><command>systemd-analyze dump</command></title>
+
+ <para>This command outputs a (usually very long) human-readable serialization of the complete server
+ state. Its format is subject to change without notice and should not be parsed by applications.</para>
+
+ <example>
+ <title>Show the internal state of user manager</title>
+
+ <programlisting>$ systemd-analyze --user dump
+Timestamp userspace: Thu 2019-03-14 23:28:07 CET
+Timestamp finish: Thu 2019-03-14 23:28:07 CET
+Timestamp generators-start: Thu 2019-03-14 23:28:07 CET
+Timestamp generators-finish: Thu 2019-03-14 23:28:07 CET
+Timestamp units-load-start: Thu 2019-03-14 23:28:07 CET
+Timestamp units-load-finish: Thu 2019-03-14 23:28:07 CET
+-> Unit proc-timer_list.mount:
+ Description: /proc/timer_list
+ ...
+-> Unit default.target:
+ Description: Main user target
+...
+</programlisting>
+ </example>
+ </refsect2>
+
+ <refsect2>
+ <title><command>systemd-analyze plot</command></title>
+
+ <para>This command prints an SVG graphic detailing which system services have been started at what
+ time, highlighting the time they spent on initialization.</para>
+
+ <example>
+ <title><command>Plot a bootchart</command></title>
+
+ <programlisting>$ systemd-analyze plot >bootup.svg
+$ eog bootup.svg&amp;
+</programlisting>
+ </example>
+ </refsect2>
+
+ <refsect2>
+ <title><command>systemd-analyze dot [<replaceable>pattern</replaceable>...]</command></title>
+
+ <para>This command generates textual dependency graph description in dot format for further processing
+ with the GraphViz
+ <citerefentry project='die-net'><refentrytitle>dot</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ tool. Use a command line like <command>systemd-analyze dot | dot -Tsvg >systemd.svg</command> to
+ generate a graphical dependency tree. Unless <option>--order</option> or <option>--require</option> is
+ passed, the generated graph will show both ordering and requirement dependencies. Optional pattern
+ globbing style specifications (e.g. <filename>*.target</filename>) may be given at the end. A unit
+ dependency is included in the graph if any of these patterns match either the origin or destination
+ node.</para>
+
+ <example>
+ <title>Plot all dependencies of any unit whose name starts with <literal>avahi-daemon</literal>
+ </title>
+
+ <programlisting>$ systemd-analyze dot 'avahi-daemon.*' | dot -Tsvg >avahi.svg
+$ eog avahi.svg</programlisting>
+ </example>
+
+ <example>
+ <title>Plot the dependencies between all known target units</title>
- <example>
- <title>Showing logind configuration</title>
- <programlisting>$ systemd-analyze cat-config systemd/logind.conf
+ <programlisting>$ systemd-analyze dot --to-pattern='*.target' --from-pattern='*.target' \
+ | dot -Tsvg >targets.svg
+$ eog targets.svg</programlisting>
+ </example>
+ </refsect2>
+
+ <refsect2>
+ <title><command>systemd-analyze unit-paths</command></title>
+
+ <para>This command outputs a list of all directories from which unit files, <filename>.d</filename>
+ overrides, and <filename>.wants</filename>, <filename>.requires</filename> symlinks may be
+ loaded. Combine with <option>--user</option> to retrieve the list for the user manager instance, and
+ <option>--global</option> for the global configuration of user manager instances.</para>
+
+ <example>
+ <title><command>Show all paths for generated units</command></title>
+
+ <programlisting>$ systemd-analyze unit-paths | grep '^/run'
+/run/systemd/system.control
+/run/systemd/transient
+/run/systemd/generator.early
+/run/systemd/system
+/run/systemd/system.attached
+/run/systemd/generator
+/run/systemd/generator.late
+</programlisting>
+ </example>
+
+ <para>Note that this verb prints the list that is compiled into <command>systemd-analyze</command>
+ itself, and does not comunicate with the running manager. Use
+ <programlisting>systemctl [--user] [--global] show -p UnitPath --value</programlisting>
+ to retrieve the actual list that the manager uses, with any empty directories omitted.</para>
+ </refsect2>
+
+ <refsect2>
+ <title><command>systemd-analyze syscall-filter <optional><replaceable>SET</replaceable>...</optional></command></title>
+
+ <para>This command will list system calls contained in the specified system call set
+ <replaceable>SET</replaceable>, or all known sets if no sets are specified. Argument
+ <replaceable>SET</replaceable> must include the <literal>@</literal> prefix.</para>
+ </refsect2>
+
+ <refsect2>
+ <title><command>systemd-analyze calendar <replaceable>EXPRESSION</replaceable>...</command></title>
+
+ <para>This command will parse and normalize repetitive calendar time events, and will calculate when
+ they elapse next. This takes the same input as the <varname>OnCalendar=</varname> setting in
+ <citerefentry><refentrytitle>systemd.timer</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+ following the syntax described in
+ <citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry>. By
+ default, only the next time the calendar expression will elapse is shown; use
+ <option>--iterations=</option> to show the specified number of next times the expression
+ elapses.</para>
+
+ <example>
+ <title>Show leap days in the near future</title>
+
+ <programlisting>$ systemd-analyze calendar --iterations=5 '*-2-29 0:0:0'
+ Original form: *-2-29 0:0:0
+Normalized form: *-02-29 00:00:00
+ Next elapse: Sat 2020-02-29 00:00:00 UTC
+ From now: 11 months 15 days left
+ Iter. #2: Thu 2024-02-29 00:00:00 UTC
+ From now: 4 years 11 months left
+ Iter. #3: Tue 2028-02-29 00:00:00 UTC
+ From now: 8 years 11 months left
+ Iter. #4: Sun 2032-02-29 00:00:00 UTC
+ From now: 12 years 11 months left
+ Iter. #5: Fri 2036-02-29 00:00:00 UTC
+ From now: 16 years 11 months left
+</programlisting>
+ </example>
+ </refsect2>
+
+ <refsect2>
+ <title><command>systemd-analyze timespan <replaceable>EXPRESSION</replaceable>...</command></title>
+
+ <para>This command parses a time span and outputs the normalized form and the equivalent value in
+ microseconds. The time span should adhere to the same syntax documented in
+ <citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry>.
+ Values without associated magnitudes are parsed as seconds.</para>
+
+ <example>
+ <title>Show parsing of timespans</title>
+
+ <programlisting>$ systemd-analyze timespan 1s 300s '1year 0.000001s'
+Original: 1s
+ μs: 1000000
+ Human: 1s
+
+Original: 300s
+ μs: 300000000
+ Human: 5min
+
+Original: 1year 0.000001s
+ μs: 31557600000001
+ Human: 1y 1us
+</programlisting>
+ </example>
+ </refsect2>
+
+ <refsect2>
+ <title><command>systemd-analyze cat-config</command>
+ <replaceable>NAME</replaceable>|<replaceable>PATH</replaceable>...</title>
+
+ <para>This command is similar to <command>systemctl cat</command>, but operates on config files. It
+ will copy the contents of a config file and any drop-ins to standard output, using the usual systemd
+ set of directories and rules for precedence. Each argument must be either an absolute path including
+ the prefix (such as <filename>/etc/systemd/logind.conf</filename> or
+ <filename>/usr/lib/systemd/logind.conf</filename>), or a name relative to the prefix (such as
+ <filename>systemd/logind.conf</filename>).</para>
+
+ <example>
+ <title>Showing logind configuration</title>
+ <programlisting>$ systemd-analyze cat-config systemd/logind.conf
# /etc/systemd/logind.conf
...
[Login]
@@ -201,90 +431,122 @@ NAutoVTs=8
# /etc/systemd/logind.conf.d/50-override.conf
... some administrator override
- </programlisting>
- </example>
-
- <para><command>systemd-analyze unit-paths</command> outputs a list of all
- directories from which unit files, <filename>.d</filename> overrides, and
- <filename>.wants</filename>, <filename>.requires</filename> symlinks may be
- loaded. Combine with <option>--user</option> to retrieve the list for the user
- manager instance, and <option>--global</option> for the global configuration of
- user manager instances. Note that this verb prints the list that is compiled into
- <command>systemd-analyze</command> itself, and does not comunicate with the
- running manager. Use
- <programlisting>systemctl [--user] [--global] show -p UnitPath --value</programlisting>
- to retrieve the actual list that the manager uses, with any empty directories
- omitted.</para>
-
- <para><command>systemd-analyze log-level</command>
- prints the current log level of the <command>systemd</command> daemon.
- If an optional argument <replaceable>LEVEL</replaceable> is provided, then the command changes the current log
- level of the <command>systemd</command> daemon to <replaceable>LEVEL</replaceable> (accepts the same values as
- <option>--log-level=</option> described in
- <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>).</para>
-
- <para><command>systemd-analyze log-target</command>
- prints the current log target of the <command>systemd</command> daemon.
- If an optional argument <replaceable>TARGET</replaceable> is provided, then the command changes the current log
- target of the <command>systemd</command> daemon to <replaceable>TARGET</replaceable> (accepts the same values as
- <option>--log-target=</option>, described in
- <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>).</para>
-
- <para><command>systemd-analyze syscall-filter <optional><replaceable>SET</replaceable>…</optional></command>
- will list system calls contained in the specified system call set <replaceable>SET</replaceable>,
- or all known sets if no sets are specified. Argument <replaceable>SET</replaceable> must include
- the <literal>@</literal> prefix.</para>
-
- <para><command>systemd-analyze verify</command> will load unit files and print
- warnings if any errors are detected. Files specified on the command line will be
- loaded, but also any other units referenced by them. The full unit search path is
- formed by combining the directories for all command line arguments, and the usual unit
- load paths (variable <varname>$SYSTEMD_UNIT_PATH</varname> is supported, and may be
- used to replace or augment the compiled in set of unit load paths; see
- <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>).
- All units files present in the directories containing the command line arguments will
- be used in preference to the other paths.</para>
-
- <para><command>systemd-analyze calendar</command> will parse and normalize repetitive calendar time events, and
- will calculate when they will elapse next. This takes the same input as the <varname>OnCalendar=</varname> setting
- in <citerefentry><refentrytitle>systemd.timer</refentrytitle><manvolnum>5</manvolnum></citerefentry>, following the
- syntax described in
- <citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para>
-
- <para><command>systemd-analyze service-watchdogs</command>
- prints the current state of service runtime watchdogs of the <command>systemd</command> daemon.
- If an optional boolean argument is provided, then globally enables or disables the service
- runtime watchdogs (<option>WatchdogSec=</option>) and emergency actions (e.g.
- <option>OnFailure=</option> or <option>StartLimitAction=</option>); see
- <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
- The hardware watchdog is not affected by this setting.</para>
-
- <para><command>systemd-analyze security</command> analyzes the security and sandboxing settings of one or more
- specified service units. If at least one unit name is specified the security settings of the specified service
- units are inspected and a detailed analysis is shown. If no unit name is specified, all currently loaded,
- long-running service units are inspected and a terse table with results shown. The command checks for various
- security-related service settings, assigning each a numeric "exposure level" value, depending on how important a
- setting is. It then calculates an overall exposure level for the whole unit, which is an estimation in the range
- 0.0…10.0 indicating how exposed a service is security-wise. High exposure levels indicate very little applied
- sandboxing. Low exposure levels indicate tight sandboxing and strongest security restrictions. Note that this only
- analyzes the per-service security features systemd itself implements. This means that any additional security
- mechanisms applied by the service code itself are not accounted for. The exposure level determined this way should
- not be misunderstood: a high exposure level neither means that there is no effective sandboxing applied by the
- service code itself, nor that the service is actually vulnerable to remote or local attacks. High exposure levels
- do indicate however that most likely the service might benefit from additional settings applied to them. Please
- note that many of the security and sandboxing settings individually can be circumvented — unless combined with
- others. For example, if a service retains the privilege to establish or undo mount points many of the sandboxing
- options can be undone by the service code itself. Due to that is essential that each service uses the most
- comprehensive and strict sandboxing and security settings possible. The tool will take into account some of these
- combinations and relationships between the settings, but not all. Also note that the security and sandboxing
- settings analyzed here only apply to the operations executed by the service code itself. If a service has access to
- an IPC system (such as D-Bus) it might request operations from other services that are not subject to the same
- restrictions. Any comprehensive security and sandboxing analysis is hence incomplete if the IPC access policy is
- not validated too.</para>
+ </programlisting>
+ </example>
+ </refsect2>
- <para>If no command is passed, <command>systemd-analyze
- time</command> is implied.</para>
+ <refsect2>
+ <title><command>systemd-analyze verify <replaceable>FILE</replaceable>...</command></title>
+
+ <para>This command will load unit files and print warnings if any errors are detected. Files specified
+ on the command line will be loaded, but also any other units referenced by them. The full unit search
+ path is formed by combining the directories for all command line arguments, and the usual unit load
+ paths (variable <varname>$SYSTEMD_UNIT_PATH</varname> is supported, and may be used to replace or
+ augment the compiled in set of unit load paths; see
+ <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>). All
+ units files present in the directories containing the command line arguments will be used in preference
+ to the other paths.</para>
+
+ <para>The following errors are currently detected:</para>
+ <itemizedlist>
+ <listitem><para>unknown sections and directives,</para></listitem>
+
+ <listitem><para>missing dependencies which are required to start the given unit,</para></listitem>
+
+ <listitem><para>man pages listed in <varname>Documentation=</varname> which are not found in the
+ system,</para></listitem>
+
+ <listitem><para>commands listed in <varname>ExecStart=</varname> and similar which are not found in
+ the system or not executable.</para></listitem>
+ </itemizedlist>
+ <example>
+ <title>Misspelt directives</title>
+
+ <programlisting>$ cat ./user.slice
+[Unit]
+WhatIsThis=11
+Documentation=man:nosuchfile(1)
+Requires=different.service
+
+[Service]
+Description=x
+
+$ systemd-analyze verify ./user.slice
+[./user.slice:9] Unknown lvalue 'WhatIsThis' in section 'Unit'
+[./user.slice:13] Unknown section 'Service'. Ignoring.
+Error: org.freedesktop.systemd1.LoadFailed:
+ Unit different.service failed to load:
+ No such file or directory.
+Failed to create user.slice/start: Invalid argument
+user.slice: man nosuchfile(1) command failed with code 16
+ </programlisting>
+ </example>
+
+ <example>
+ <title>Missing service units</title>
+
+ <programlisting>$ tail ./a.socket ./b.socket
+==> ./a.socket &lt;==
+[Socket]
+ListenStream=100
+
+==> ./b.socket &lt;==
+[Socket]
+ListenStream=100
+Accept=yes
+
+$ systemd-analyze verify ./a.socket ./b.socket
+Service a.service not loaded, a.socket cannot be started.
+Service b@0.service not loaded, b.socket cannot be started.
+ </programlisting>
+ </example>
+ </refsect2>
+
+ <refsect2>
+ <title><command>systemd-analyze security <optional><replaceable>UNIT</replaceable>...</optional></command></title>
+
+ <para>This command analyzes the security and sandboxing settings of one or more specified service
+ units. If at least one unit name is specified the security settings of the specified service units are
+ inspected and a detailed analysis is shown. If no unit name is specified, all currently loaded,
+ long-running service units are inspected and a terse table with results shown. The command checks for
+ various security-related service settings, assigning each a numeric "exposure level" value, depending
+ on how important a setting is. It then calculates an overall exposure level for the whole unit, which
+ is an estimation in the range 0.0…10.0 indicating how exposed a service is security-wise. High exposure
+ levels indicate very little applied sandboxing. Low exposure levels indicate tight sandboxing and
+ strongest security restrictions. Note that this only analyzes the per-service security features systemd
+ itself implements. This means that any additional security mechanisms applied by the service code
+ itself are not accounted for. The exposure level determined this way should not be misunderstood: a
+ high exposure level neither means that there is no effective sandboxing applied by the service code
+ itself, nor that the service is actually vulnerable to remote or local attacks. High exposure levels do
+ indicate however that most likely the service might benefit from additional settings applied to
+ them.</para>
+
+ <para>Please note that many of the security and sandboxing settings individually can be circumvented —
+ unless combined with others. For example, if a service retains the privilege to establish or undo mount
+ points many of the sandboxing options can be undone by the service code itself. Due to that is
+ essential that each service uses the most comprehensive and strict sandboxing and security settings
+ possible. The tool will take into account some of these combinations and relationships between the
+ settings, but not all. Also note that the security and sandboxing settings analyzed here only apply to
+ the operations executed by the service code itself. If a service has access to an IPC system (such as
+ D-Bus) it might request operations from other services that are not subject to the same
+ restrictions. Any comprehensive security and sandboxing analysis is hence incomplete if the IPC access
+ policy is not validated too.</para>
+
+ <example>
+ <title>Analyze <filename noindex="true">systemd-logind.service</filename></title>
+
+ <programlisting>$ systemd-analyze security --no-pager systemd-logind.service
+ NAME DESCRIPTION EXPOSURE
+✗ PrivateNetwork= Service has access to the host's network 0.5
+✗ User=/DynamicUser= Service runs as root user 0.4
+✗ DeviceAllow= Service has no device ACL 0.2
+✓ IPAddressDeny= Service blocks all IP address ranges
+...
+→ Overall exposure level for systemd-logind.service: 4.1 OK 🙂
+</programlisting>
+ </example>
+ </refsect2>
</refsect1>
<refsect1>
@@ -408,88 +670,6 @@ NAutoVTs=8
otherwise.</para>
</refsect1>
- <refsect1>
- <title>Examples for <command>dot</command></title>
-
- <example>
- <title>Plots all dependencies of any unit whose name starts with
- <literal>avahi-daemon</literal></title>
-
- <programlisting>$ systemd-analyze dot 'avahi-daemon.*' | dot -Tsvg > avahi.svg
-$ eog avahi.svg</programlisting>
- </example>
-
- <example>
- <title>Plots the dependencies between all known target units</title>
-
- <programlisting>$ systemd-analyze dot --to-pattern='*.target' --from-pattern='*.target' | dot -Tsvg > targets.svg
-$ eog targets.svg</programlisting>
- </example>
- </refsect1>
-
- <refsect1>
- <title>Examples for <command>verify</command></title>
-
- <para>The following errors are currently detected:</para>
- <itemizedlist>
- <listitem><para>unknown sections and directives,
- </para></listitem>
-
- <listitem><para>missing dependencies which are required to start
- the given unit,</para></listitem>
-
- <listitem><para>man pages listed in
- <varname>Documentation=</varname> which are not found in the
- system,</para></listitem>
-
- <listitem><para>commands listed in <varname>ExecStart=</varname>
- and similar which are not found in the system or not
- executable.</para></listitem>
- </itemizedlist>
-
- <example>
- <title>Misspelt directives</title>
-
- <programlisting>$ cat ./user.slice
-[Unit]
-WhatIsThis=11
-Documentation=man:nosuchfile(1)
-Requires=different.service
-
-[Service]
-Description=x
-
-$ systemd-analyze verify ./user.slice
-[./user.slice:9] Unknown lvalue 'WhatIsThis' in section 'Unit'
-[./user.slice:13] Unknown section 'Service'. Ignoring.
-Error: org.freedesktop.systemd1.LoadFailed:
- Unit different.service failed to load:
- No such file or directory.
-Failed to create user.slice/start: Invalid argument
-user.slice: man nosuchfile(1) command failed with code 16
- </programlisting>
- </example>
-
- <example>
- <title>Missing service units</title>
-
- <programlisting>$ tail ./a.socket ./b.socket
-==> ./a.socket &lt;==
-[Socket]
-ListenStream=100
-
-==> ./b.socket &lt;==
-[Socket]
-ListenStream=100
-Accept=yes
-
-$ systemd-analyze verify ./a.socket ./b.socket
-Service a.service not loaded, a.socket cannot be started.
-Service b@0.service not loaded, b.socket cannot be started.
- </programlisting>
- </example>
- </refsect1>
-
<xi:include href="less-variables.xml" />
<refsect1>

View File

@ -0,0 +1,132 @@
From ac7db0c5b48f1090f77dbcfa0a1e0dc08d5c471e Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <fsumsal@redhat.com>
Date: Mon, 14 Oct 2019 15:26:48 +0200
Subject: [PATCH] travis: move to CentOS 8 docker images
As the CentOS 8 Docker images is finally out, we can use it and drop the
plethora of workarounds we had to implement to compile RHEL8 systemd on
CentOS 7.
Resolves: #1761519
---
.travis.yml | 22 ++++++++++------------
ci/travis-centos-rhel8.sh | 32 +++++++++-----------------------
2 files changed, 19 insertions(+), 35 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index 0010da5784..70c60cf24e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -9,42 +9,40 @@ env:
jobs:
include:
- - name: CentOS 7
+ - name: CentOS 8
language: bash
env:
- - CENTOS_RELEASE="centos7"
+ - CENTOS_RELEASE="centos8"
- CONT_NAME="systemd-centos-$CENTOS_RELEASE"
- DOCKER_EXEC="docker exec -ti $CONT_NAME"
before_install:
- sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
- docker --version
install:
- - if [ -f meson.build ]; then RHEL_VERSION=rhel8; else RHEL_VERSION=rhel7; fi
- - $CI_ROOT/travis-centos-${RHEL_VERSION}.sh SETUP
+ - $CI_ROOT/travis-centos-rhel8.sh SETUP
script:
- set -e
# Build systemd
- - $CI_ROOT/travis-centos-${RHEL_VERSION}.sh RUN
+ - $CI_ROOT/travis-centos-rhel8.sh RUN
- set +e
after_script:
- - $CI_ROOT/travis-centos-${RHEL_VERSION}.sh CLEANUP
+ - $CI_ROOT/travis-centos-rhel8.sh CLEANUP
- - name: CentOS 7 (ASan+UBSan)
+ - name: CentOS 8 (ASan+UBSan)
language: bash
env:
- - CENTOS_RELEASE="centos7"
+ - CENTOS_RELEASE="centos8"
- CONT_NAME="systemd-centos-$CENTOS_RELEASE"
- DOCKER_EXEC="docker exec -ti $CONT_NAME"
before_install:
- sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
- docker --version
install:
- - if [ -f meson.build ]; then RHEL_VERSION=rhel8; else RHEL_VERSION=rhel7; fi
- - $CI_ROOT/travis-centos-${RHEL_VERSION}.sh SETUP
+ - $CI_ROOT/travis-centos-rhel8.sh SETUP
script:
- set -e
# Build systemd
- - $CI_ROOT/travis-centos-${RHEL_VERSION}.sh RUN_ASAN
+ - $CI_ROOT/travis-centos-rhel8.sh RUN_ASAN
- set +e
after_script:
- - $CI_ROOT/travis-centos-${RHEL_VERSION}.sh CLEANUP
+ - $CI_ROOT/travis-centos-rhel8.sh CLEANUP
diff --git a/ci/travis-centos-rhel8.sh b/ci/travis-centos-rhel8.sh
index c3d1018682..ade44a0413 100755
--- a/ci/travis-centos-rhel8.sh
+++ b/ci/travis-centos-rhel8.sh
@@ -15,10 +15,7 @@ CONT_NAME="${CONT_NAME:-centos-$CENTOS_RELEASE-$RANDOM}"
DOCKER_EXEC="${DOCKER_EXEC:-docker exec -it $CONT_NAME}"
DOCKER_RUN="${DOCKER_RUN:-docker run}"
REPO_ROOT="${REPO_ROOT:-$PWD}"
-ADDITIONAL_DEPS=(systemd-ci-environment libidn2-devel python-lxml python36 ninja-build libasan net-tools strace nc busybox e2fsprogs quota dnsmasq)
-# Repo with additional depencencies to compile newer systemd on CentOS 7
-COPR_REPO="https://copr.fedorainfracloud.org/coprs/mrc0mmand/systemd-centos-ci/repo/epel-7/mrc0mmand-systemd-centos-ci-epel-7.repo"
-COPR_REPO_PATH="/etc/yum.repos.d/${COPR_REPO##*/}"
+ADDITIONAL_DEPS=(libasan libubsan net-tools strace nc e2fsprogs quota dnsmasq)
# RHEL8 options
CONFIGURE_OPTS=(
-Dsysvinit-path=/etc/rc.d/init.d
@@ -95,18 +92,14 @@ for phase in "${PHASES[@]}"; do
-dit --net=host centos:$CENTOS_RELEASE /sbin/init
# Beautiful workaround for Fedora's version of Docker
sleep 1
- $DOCKER_EXEC yum makecache
- $DOCKER_EXEC curl "$COPR_REPO" -o "$COPR_REPO_PATH"
- $DOCKER_EXEC yum -q -y install epel-release yum-utils
- $DOCKER_EXEC yum-config-manager -q --enable epel
- $DOCKER_EXEC yum -y upgrade
- # Install necessary build/test requirements
- $DOCKER_EXEC yum -y install "${ADDITIONAL_DEPS[@]}"
- $DOCKER_EXEC python3.6 -m ensurepip
- $DOCKER_EXEC python3.6 -m pip install meson
- # Create necessary symlinks
- $DOCKER_EXEC ln --force -s /usr/bin/python3.6 /usr/bin/python3
- $DOCKER_EXEC ln --force -s /usr/bin/ninja-build /usr/bin/ninja
+ $DOCKER_EXEC dnf makecache
+ # Install and enable EPEL
+ $DOCKER_EXEC dnf -q -y install epel-release dnf-utils "${ADDITIONAL_DEPS[@]}"
+ $DOCKER_EXEC dnf config-manager -q --enable epel
+ # Upgrade the container to get the most recent environment
+ $DOCKER_EXEC dnf -y upgrade
+ # Install systemd's build dependencies
+ $DOCKER_EXEC dnf -q -y --enablerepo "PowerTools" builddep systemd
;;
RUN)
info "Run phase"
@@ -117,16 +110,9 @@ for phase in "${PHASES[@]}"; do
# unexpected fails due to incompatibilities with older systemd
$DOCKER_EXEC ninja -C build install
docker restart $CONT_NAME
- # "Mask" the udev-test.pl, as it requires newer version of systemd-detect-virt
- # and it's pointless to run it on a VM in a Docker container...
- echo -ne "#!/usr/bin/perl\nexit(0);\n" > "test/udev-test.pl"
$DOCKER_EXEC ninja -C build test
;;
RUN_ASAN|RUN_CLANG_ASAN)
- # Let's install newer gcc for proper ASan/UBSan support
- $DOCKER_EXEC yum -y install centos-release-scl
- $DOCKER_EXEC yum -y install devtoolset-8 devtoolset-8-libasan-devel libasan5 devtoolset-8-libubsan-devel libubsan1
- $DOCKER_EXEC bash -c "echo 'source scl_source enable devtoolset-8' >> /root/.bashrc"
# Note to my future frustrated self: docker exec runs the given command
# as sh -c 'command' - which means both .bash_profile and .bashrc will
# be ignored. That's because .bash_profile is sourced for LOGIN shells (i.e.

View File

@ -0,0 +1,50 @@
From 5b14988845b591f6fa2fc1e032618fe882827f4a Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <fsumsal@redhat.com>
Date: Mon, 14 Oct 2019 16:22:51 +0200
Subject: [PATCH] travis: drop SCL remains
The `bash -ic` wrapper existed solely to make SCL work as expected
Resolves: #1761519
---
ci/travis-centos-rhel8.sh | 16 +++-------------
1 file changed, 3 insertions(+), 13 deletions(-)
diff --git a/ci/travis-centos-rhel8.sh b/ci/travis-centos-rhel8.sh
index ade44a0413..da131c726b 100755
--- a/ci/travis-centos-rhel8.sh
+++ b/ci/travis-centos-rhel8.sh
@@ -113,22 +113,12 @@ for phase in "${PHASES[@]}"; do
$DOCKER_EXEC ninja -C build test
;;
RUN_ASAN|RUN_CLANG_ASAN)
- # Note to my future frustrated self: docker exec runs the given command
- # as sh -c 'command' - which means both .bash_profile and .bashrc will
- # be ignored. That's because .bash_profile is sourced for LOGIN shells (i.e.
- # sh -l), whereas .bashrc is sourced for NON-LOGIN INTERACTIVE shells
- # (i.e. sh -i).
- # As the default docker exec command lacks either of those options,
- # we need to use a wrapper command which runs the wanted command
- # under an explicit bash -i, so the SCL source above works properly.
- docker exec -it $CONT_NAME bash -ic 'gcc --version'
-
if [[ "$phase" = "RUN_CLANG_ASAN" ]]; then
ENV_VARS="-e CC=clang -e CXX=clang++"
MESON_ARGS="-Db_lundef=false" # See https://github.com/mesonbuild/meson/issues/764
fi
- docker exec $ENV_VARS -it $CONT_NAME bash -ic "meson build --werror -Dtests=unsafe -Db_sanitize=address,undefined $MESON_ARGS ${CONFIGURE_OPTS[@]}"
- docker exec -it $CONT_NAME bash -ic 'ninja -v -C build'
+ docker exec $ENV_VARS -it $CONT_NAME meson build --werror -Dtests=unsafe -Db_sanitize=address,undefined $MESON_ARGS ${CONFIGURE_OPTS[@]}
+ docker exec -it $CONT_NAME ninja -v -C build
# Never remove halt_on_error from UBSAN_OPTIONS. See https://github.com/systemd/systemd/commit/2614d83aa06592aedb.
travis_wait docker exec --interactive=false \
@@ -136,7 +126,7 @@ for phase in "${PHASES[@]}"; do
-e ASAN_OPTIONS=strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1 \
-e "TRAVIS=$TRAVIS" \
-t $CONT_NAME \
- bash -ic 'meson test --timeout-multiplier=3 -C ./build/ --print-errorlogs'
+ meson test --timeout-multiplier=3 -C ./build/ --print-errorlogs
;;
CLEANUP)
info "Cleanup phase"

View File

@ -0,0 +1,110 @@
From 8bd791fb3a8e85063e297204bdef8004aacd22b1 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Wed, 8 Aug 2018 18:27:15 +0900
Subject: [PATCH] syslog: fix segfault in syslog_parse_priority()
(cherry picked from commit a5ee33b951cfa22db53d0274c9c6c0d9d4dae39d)
Resolves: #1761519
---
src/basic/syslog-util.c | 20 +++++++++++---------
src/journal/test-journal-syslog.c | 20 ++++++++++++++++++++
2 files changed, 31 insertions(+), 9 deletions(-)
diff --git a/src/basic/syslog-util.c b/src/basic/syslog-util.c
index 21461fa581..fe129482f3 100644
--- a/src/basic/syslog-util.c
+++ b/src/basic/syslog-util.c
@@ -10,7 +10,8 @@
int syslog_parse_priority(const char **p, int *priority, bool with_facility) {
int a = 0, b = 0, c = 0;
- int k;
+ const char *end;
+ size_t k;
assert(p);
assert(*p);
@@ -19,21 +20,22 @@ int syslog_parse_priority(const char **p, int *priority, bool with_facility) {
if ((*p)[0] != '<')
return 0;
- if (!strchr(*p, '>'))
+ end = strchr(*p, '>');
+ if (!end)
return 0;
- if ((*p)[2] == '>') {
+ k = end - *p;
+ assert(k > 0);
+
+ if (k == 2)
c = undecchar((*p)[1]);
- k = 3;
- } else if ((*p)[3] == '>') {
+ else if (k == 3) {
b = undecchar((*p)[1]);
c = undecchar((*p)[2]);
- k = 4;
- } else if ((*p)[4] == '>') {
+ } else if (k == 4) {
a = undecchar((*p)[1]);
b = undecchar((*p)[2]);
c = undecchar((*p)[3]);
- k = 5;
} else
return 0;
@@ -46,7 +48,7 @@ int syslog_parse_priority(const char **p, int *priority, bool with_facility) {
else
*priority = (*priority & LOG_FACMASK) | c;
- *p += k;
+ *p += k + 1;
return 1;
}
diff --git a/src/journal/test-journal-syslog.c b/src/journal/test-journal-syslog.c
index 7294cde032..120477cc9f 100644
--- a/src/journal/test-journal-syslog.c
+++ b/src/journal/test-journal-syslog.c
@@ -4,6 +4,7 @@
#include "journald-syslog.h"
#include "macro.h"
#include "string-util.h"
+#include "syslog-util.h"
static void test_syslog_parse_identifier(const char *str,
const char *ident, const char *pid, const char *rest, int ret) {
@@ -19,6 +20,17 @@ static void test_syslog_parse_identifier(const char *str,
assert_se(streq(buf, rest));
}
+static void test_syslog_parse_priority(const char *str, int priority, int ret) {
+ const char *buf = str;
+ int priority2, ret2;
+
+ ret2 = syslog_parse_priority(&buf, &priority2, false);
+
+ assert_se(ret == ret2);
+ if (ret2 == 1)
+ assert_se(priority == priority2);
+}
+
int main(void) {
test_syslog_parse_identifier("pidu[111]: xxx", "pidu", "111", "xxx", 11);
test_syslog_parse_identifier("pidu: xxx", "pidu", NULL, "xxx", 6);
@@ -33,5 +45,13 @@ int main(void) {
test_syslog_parse_identifier("pidu: ", "pidu", NULL, "", 6);
test_syslog_parse_identifier("pidu : ", NULL, NULL, "pidu : ", 0);
+ test_syslog_parse_priority("<>", 0, 0);
+ test_syslog_parse_priority("<>aaa", 0, 0);
+ test_syslog_parse_priority("<aaaa>", 0, 0);
+ test_syslog_parse_priority("<aaaa>aaa", 0, 0);
+ test_syslog_parse_priority(" <aaaa>", 0, 0);
+ test_syslog_parse_priority(" <aaaa>aaa", 0, 0);
+ /* TODO: add test cases of valid priorities */
+
return 0;
}

View File

@ -0,0 +1,45 @@
From fbe5fa22f5b99d4e444db54aadb661e9c932eb6c Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Fri, 16 Nov 2018 13:00:40 +0100
Subject: [PATCH] sd-bus: make strict asan shut up
asan doesn't like it if we use strndup() (i.e. a string function) on a
non-NULL terminated buffer (i.e. something that isn't really a string).
Let's hence use memdup_suffix0() instead of strndup(), which is more
appropriate for binary data that is to become a string.
Fixes: #10385
(cherry picked from commit ac0a94f7438b49a0890d9806db1fa211a5bca10a)
Resolves: #1761519
---
src/libsystemd/sd-bus/bus-message.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c
index 53cbd675b7..19cb2b9a97 100644
--- a/src/libsystemd/sd-bus/bus-message.c
+++ b/src/libsystemd/sd-bus/bus-message.c
@@ -5101,6 +5101,7 @@ int bus_message_parse_fields(sd_bus_message *m) {
return -EBADMSG;
if (*p == 0) {
+ char *k;
size_t l;
/* We found the beginning of the signature
@@ -5114,9 +5115,11 @@ int bus_message_parse_fields(sd_bus_message *m) {
p[1 + l - 1] != SD_BUS_TYPE_STRUCT_END)
return -EBADMSG;
- if (free_and_strndup(&m->root_container.signature,
- p + 1 + 1, l - 2) < 0)
+ k = memdup_suffix0(p + 1 + 1, l - 2);
+ if (!k)
return -ENOMEM;
+
+ free_and_replace(m->root_container.signature, k);
break;
}

View File

@ -0,0 +1,43 @@
From 2f44943836b69455792a5422673f8a69bc9705ba Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <fsumsal@redhat.com>
Date: Mon, 14 Oct 2019 17:14:35 +0200
Subject: [PATCH] travis: don't run slow tests under ASan/UBSan
Resolves: #1761519
---
ci/travis-centos-rhel8.sh | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/ci/travis-centos-rhel8.sh b/ci/travis-centos-rhel8.sh
index da131c726b..a1502e15ee 100755
--- a/ci/travis-centos-rhel8.sh
+++ b/ci/travis-centos-rhel8.sh
@@ -65,10 +65,6 @@ CONFIGURE_OPTS=(
-Dnetworkd=false
-Dtimesyncd=false
-Ddefault-hierarchy=legacy
- # Custom options
- -Dslow-tests=true
- -Dtests=unsafe
- -Dinstall-tests=true
)
function info() {
@@ -104,7 +100,7 @@ for phase in "${PHASES[@]}"; do
RUN)
info "Run phase"
# Build systemd
- docker exec -it -e CFLAGS='-g -O0 -ftrapv' $CONT_NAME meson build "${CONFIGURE_OPTS[@]}"
+ docker exec -it -e CFLAGS='-g -O0 -ftrapv' $CONT_NAME meson build -Dtests=unsafe -Dslow-tests=true "${CONFIGURE_OPTS[@]}"
$DOCKER_EXEC ninja -v -C build
# Let's install the new systemd and "reboot" the container to avoid
# unexpected fails due to incompatibilities with older systemd
@@ -117,7 +113,7 @@ for phase in "${PHASES[@]}"; do
ENV_VARS="-e CC=clang -e CXX=clang++"
MESON_ARGS="-Db_lundef=false" # See https://github.com/mesonbuild/meson/issues/764
fi
- docker exec $ENV_VARS -it $CONT_NAME meson build --werror -Dtests=unsafe -Db_sanitize=address,undefined $MESON_ARGS ${CONFIGURE_OPTS[@]}
+ docker exec $ENV_VARS -it $CONT_NAME meson build --werror -Dtests=unsafe -Db_sanitize=address,undefined $MESON_ARGS "${CONFIGURE_OPTS[@]}"
docker exec -it $CONT_NAME ninja -v -C build
# Never remove halt_on_error from UBSAN_OPTIONS. See https://github.com/systemd/systemd/commit/2614d83aa06592aedb.

View File

@ -0,0 +1,67 @@
From 6240d78097c6f828aa2ca3b50ac322b41dc41fd1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Fri, 23 Aug 2019 11:34:45 +0200
Subject: [PATCH] kernel-install: do not require non-empty kernel cmdline
When booting with Fedora-Server-dvd-x86_64-30-20190411.n.0.iso,
/proc/cmdline is empty (libvirt, qemu host with bios, not sure if that
matters), after installation to disk, anaconda would "crash" in kernel-core
%posttrans, after calling kernel-install, because dracut would fail
with
> Could not determine the kernel command line parameters.
> Please specify the kernel command line in /etc/kernel/cmdline!
I guess it's legitimate, even if unusual, to have no cmdline parameters.
Two changes are done in this patch:
1. do not fail if the cmdline is empty.
2. if /usr/lib/kernel/cmdline or /etc/kernel/cmdline are present, but
empty, ignore /proc/cmdline. If there's explicit configuration to
have empty cmdline, don't ignore it.
The same change was done in dracut:
https://github.com/dracutdevs/dracut/pull/561.
(cherry picked from commit 88e1306af6380794842fb31108ba67895799fab4)
Resolves: #1701454
---
src/kernel-install/90-loaderentry.install | 14 ++++----------
1 file changed, 4 insertions(+), 10 deletions(-)
diff --git a/src/kernel-install/90-loaderentry.install b/src/kernel-install/90-loaderentry.install
index a271cdb8a0..1619301536 100644
--- a/src/kernel-install/90-loaderentry.install
+++ b/src/kernel-install/90-loaderentry.install
@@ -43,13 +43,13 @@ if ! [[ $PRETTY_NAME ]]; then
PRETTY_NAME="Linux $KERNEL_VERSION"
fi
-declare -a BOOT_OPTIONS
-
if [[ -f /etc/kernel/cmdline ]]; then
read -r -d '' -a BOOT_OPTIONS < /etc/kernel/cmdline
-fi
+elif [[ -f /usr/lib/kernel/cmdline ]]; then
+ read -r -d '' -a BOOT_OPTIONS < /usr/lib/kernel/cmdline
+else
+ declare -a BOOT_OPTIONS
-if ! [[ ${BOOT_OPTIONS[*]} ]]; then
read -r -d '' -a line < /proc/cmdline
for i in "${line[@]}"; do
[[ "${i#initrd=*}" != "$i" ]] && continue
@@ -57,12 +57,6 @@ if ! [[ ${BOOT_OPTIONS[*]} ]]; then
done
fi
-if ! [[ ${BOOT_OPTIONS[*]} ]]; then
- echo "Could not determine the kernel command line parameters." >&2
- echo "Please specify the kernel command line in /etc/kernel/cmdline!" >&2
- exit 1
-fi
-
cp "$KERNEL_IMAGE" "$BOOT_DIR_ABS/linux" &&
chown root:root "$BOOT_DIR_ABS/linux" &&
chmod 0644 "$BOOT_DIR_ABS/linux" || {

View File

@ -0,0 +1,36 @@
From c6c8e0d097d6ba12471c6112c3fd339ea40329d5 Mon Sep 17 00:00:00 2001
From: Thadeu Lima de Souza Cascardo <cascardo@canonical.com>
Date: Mon, 13 May 2019 16:58:01 -0300
Subject: [PATCH] ask-password: prevent buffer overrow when reading from
keyring
When we read from keyring, a temporary buffer is allocated in order to
determine the size needed for the entire data. However, when zeroing that area,
we use the data size returned by the read instead of the lesser size allocate
for the buffer.
That will cause memory corruption that causes systemd-cryptsetup to crash
either when a single large password is used or when multiple passwords have
already been pushed to the keyring.
Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@canonical.com>
(cherry picked from commit 59c55e73eaee345e1ee67c23eace8895ed499693)
Resolves: #1752050
---
src/shared/ask-password-api.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/shared/ask-password-api.c b/src/shared/ask-password-api.c
index 682dc754fc..764ebd08e1 100644
--- a/src/shared/ask-password-api.c
+++ b/src/shared/ask-password-api.c
@@ -79,7 +79,7 @@ static int retrieve_key(key_serial_t serial, char ***ret) {
if (n < m)
break;
- explicit_bzero(p, n);
+ explicit_bzero(p, m);
free(p);
m *= 2;
}

View File

@ -0,0 +1,37 @@
From 985837dab9c892858a92ae50043843307f5e0714 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Fri, 19 Jul 2019 18:29:11 +0200
Subject: [PATCH] core: try to reopen /dev/kmsg again right after mounting /dev
I was debugging stuff during early boot, and was confused that I never
found the logs for it in kmsg. The reason for that was that /proc is
generally not mounted the first time we do log_open() and hence
log_set_target(LOG_TARGET_KMSG) we do when running as PID 1 had not
effect. A lot later during start-up we call log_open() again where this
is fixed (after the point where we close all remaining fds still open),
but in the meantime no logs every got written to kmsg. This patch fixes
that.
(cherry picked from commit 0a2eef1ee1fef74be9d12f7dc4d0006b645b579c)
Resolves: #1749212
---
src/core/main.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/core/main.c b/src/core/main.c
index 44dd8348be..af7b26d6f1 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -2215,6 +2215,11 @@ int main(int argc, char *argv[]) {
goto finish;
}
+ /* Let's open the log backend a second time, in case the first time didn't
+ * work. Quite possibly we have mounted /dev just now, so /dev/kmsg became
+ * available, and it previously wasn't. */
+ log_open();
+
r = initialize_security(
&loaded_policy,
&security_start_timestamp,

View File

@ -0,0 +1,29 @@
From 9f259b46b760b2aa08ac1fe76fe61df514e2768f Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Tue, 3 Sep 2019 10:05:42 +0200
Subject: [PATCH] buildsys: don't garbage collect sections while linking
gc-sections is actually very aggressive and garbage collects ELF
sections used by annobin gcc plugin and annocheck then reports gaps in
coverage. Let's drop that linker flag.
RHEL-only
Resolves: #1748258
---
meson.build | 2 --
1 file changed, 2 deletions(-)
diff --git a/meson.build b/meson.build
index 04b461dcd4..613a5133b6 100644
--- a/meson.build
+++ b/meson.build
@@ -357,8 +357,6 @@ if get_option('buildtype') != 'debug'
'-ffunction-sections',
'-fdata-sections',
]
-
- possible_link_flags += '-Wl,--gc-sections'
endif
add_project_arguments(cc.get_supported_arguments(possible_cc_flags), language : 'c')

View File

@ -0,0 +1,186 @@
From d6210c3d053d70175d72ed1d1719497eed76000b Mon Sep 17 00:00:00 2001
From: Jan Synacek <jsynacek@redhat.com>
Date: Thu, 17 Oct 2019 09:37:35 +0200
Subject: [PATCH] udev: introduce CONST key name
Currently, there is no way to match against system-wide constants, such
as architecture or virtualization type, without forking helper binaries.
That potentially results in a huge number of spawned processes which
output always the same answer.
This patch introduces a special CONST keyword which takes a hard-coded
string as its key and returns a value assigned to that key. Currently
implemented are CONST{arch} and CONST{virt}, which can be used to match
against the system's architecture and virtualization type.
(based on commit 4801d8afe2ff1c1c075c9f0bc5631612172e0bb7)
Resolves: #1762679
---
man/udev.xml | 26 ++++++++++++++++++++++++++
rules/40-redhat.rules | 6 +++---
src/udev/udev-rules.c | 32 ++++++++++++++++++++++++++++++++
test/rule-syntax-check.py | 2 +-
4 files changed, 62 insertions(+), 4 deletions(-)
diff --git a/man/udev.xml b/man/udev.xml
index bdf901a8f0..8c1eb41787 100644
--- a/man/udev.xml
+++ b/man/udev.xml
@@ -236,6 +236,32 @@
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>CONST{<replaceable>key</replaceable>}</varname></term>
+ <listitem>
+ <para>Match against a system-wide constant. Supported keys are:</para>
+ <variablelist>
+ <varlistentry>
+ <term><literal>arch</literal></term>
+ <listitem>
+ <para>System's architecture. See <option>ConditionArchitecture=</option> in
+ <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ for possible values.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>virt</literal></term>
+ <listitem>
+ <para>System's virtualization environment. See
+ <citerefentry><refentrytitle>systemd-detect-virt</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ for possible values.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>Unknown keys will never match.</para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><varname>TAG</varname></term>
<listitem>
diff --git a/rules/40-redhat.rules b/rules/40-redhat.rules
index fadc6e59f1..3c95cd2df0 100644
--- a/rules/40-redhat.rules
+++ b/rules/40-redhat.rules
@@ -6,11 +6,11 @@ SUBSYSTEM=="cpu", ACTION=="add", TEST=="online", ATTR{online}=="0", ATTR{online}
# Memory hotadd request
SUBSYSTEM!="memory", GOTO="memory_hotplug_end"
ACTION!="add", GOTO="memory_hotplug_end"
-PROGRAM="/bin/uname -p", RESULT=="s390*", GOTO="memory_hotplug_end"
-PROGRAM="/bin/uname -p", RESULT=="ppc64*", GOTO="memory_hotplug_end"
+CONST{arch}=="s390*", GOTO="memory_hotplug_end"
+CONST{arch}=="ppc64*", GOTO="memory_hotplug_end"
ENV{.state}="online"
-PROGRAM="/bin/systemd-detect-virt", RESULT=="none", ENV{.state}="online_movable"
+CONST{virt}=="none", ENV{.state}="online_movable"
ATTR{state}=="offline", ATTR{state}="$env{.state}"
LABEL="memory_hotplug_end"
diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c
index 58af863f3d..a246cbe67e 100644
--- a/src/udev/udev-rules.c
+++ b/src/udev/udev-rules.c
@@ -17,6 +17,7 @@
#include <unistd.h>
#include "alloc-util.h"
+#include "architecture.h"
#include "conf-files.h"
#include "dirent-util.h"
#include "escape.h"
@@ -34,6 +35,7 @@
#include "udev.h"
#include "user-util.h"
#include "util.h"
+#include "virt.h"
#define PREALLOC_TOKEN 2048
@@ -123,6 +125,7 @@ enum token_type {
TK_M_DEVLINK, /* val */
TK_M_NAME, /* val */
TK_M_ENV, /* val, attr */
+ TK_M_CONST, /* val, attr */
TK_M_TAG, /* val */
TK_M_SUBSYSTEM, /* val */
TK_M_DRIVER, /* val */
@@ -259,6 +262,7 @@ static const char *token_str(enum token_type type) {
[TK_M_DEVLINK] = "M DEVLINK",
[TK_M_NAME] = "M NAME",
[TK_M_ENV] = "M ENV",
+ [TK_M_CONST] = "M CONST",
[TK_M_TAG] = "M TAG",
[TK_M_SUBSYSTEM] = "M SUBSYSTEM",
[TK_M_DRIVER] = "M DRIVER",
@@ -370,6 +374,7 @@ static void dump_token(struct udev_rules *rules, struct token *token) {
case TK_M_SYSCTL:
case TK_M_ATTRS:
case TK_M_ENV:
+ case TK_M_CONST:
case TK_A_ATTR:
case TK_A_SYSCTL:
case TK_A_ENV:
@@ -903,6 +908,7 @@ static void rule_add_key(struct rule_tmp *rule_tmp, enum token_type type,
token->key.builtin_cmd = *(enum udev_builtin_cmd *)data;
break;
case TK_M_ENV:
+ case TK_M_CONST:
case TK_M_ATTR:
case TK_M_SYSCTL:
case TK_M_ATTRS:
@@ -1226,6 +1232,17 @@ static void add_rule(struct udev_rules *rules, char *line,
rule_add_key(&rule_tmp, TK_A_ENV, op, value, attr);
}
+ } else if (startswith(key, "CONST{")) {
+ attr = get_key_attribute(rules->udev, key + STRLEN("CONST"));
+ if (attr == NULL || !STR_IN_SET(attr, "arch", "virt"))
+ LOG_AND_RETURN("error parsing %s attribute", "CONST");
+
+ if (op == OP_REMOVE)
+ LOG_AND_RETURN("invalid %s operation", "CONST");
+
+ if (op < OP_MATCH_MAX)
+ rule_add_key(&rule_tmp, TK_M_CONST, op, value, attr);
+
} else if (streq(key, "TAG")) {
if (op < OP_MATCH_MAX)
rule_add_key(&rule_tmp, TK_M_TAG, op, value, NULL);
@@ -1855,6 +1872,21 @@ void udev_rules_apply_to_event(struct udev_rules *rules,
goto nomatch;
break;
}
+ case TK_M_CONST: {
+ const char *key_name = rules_str(rules, cur->key.attr_off);
+ const char *value = NULL;
+
+ if (streq(key_name, "arch")) {
+ value = architecture_to_string(uname_architecture());
+ } else if (streq(key_name, "virt")) {
+ value = virtualization_to_string(detect_virtualization());
+ } else
+ assert_not_reached("Invalid CONST key");
+
+ if (match_key(rules, cur, value))
+ goto nomatch;
+ break;
+ }
case TK_M_TAG: {
struct udev_list_entry *list_entry;
bool match = false;
diff --git a/test/rule-syntax-check.py b/test/rule-syntax-check.py
index c7c0a1a656..6e59f421f5 100755
--- a/test/rule-syntax-check.py
+++ b/test/rule-syntax-check.py
@@ -19,7 +19,7 @@ quoted_string_re = r'"(?:[^\\"]|\\.)*"'
no_args_tests = re.compile(r'(ACTION|DEVPATH|KERNELS?|NAME|SYMLINK|SUBSYSTEMS?|DRIVERS?|TAG|PROGRAM|RESULT|TEST)\s*(?:=|!)=\s*' + quoted_string_re + '$')
# PROGRAM can also be specified as an assignment.
program_assign = re.compile(r'PROGRAM\s*=\s*' + quoted_string_re + '$')
-args_tests = re.compile(r'(ATTRS?|ENV|TEST){([a-zA-Z0-9/_.*%-]+)}\s*(?:=|!)=\s*' + quoted_string_re + '$')
+args_tests = re.compile(r'(ATTRS?|ENV|CONST|TEST){([a-zA-Z0-9/_.*%-]+)}\s*(?:=|!)=\s*' + quoted_string_re + '$')
no_args_assign = re.compile(r'(NAME|SYMLINK|OWNER|GROUP|MODE|TAG|RUN|LABEL|GOTO|WAIT_FOR|OPTIONS|IMPORT)\s*(?:\+=|:=|=)\s*' + quoted_string_re + '$')
args_assign = re.compile(r'(ATTR|ENV|IMPORT|RUN){([a-zA-Z0-9/_.*%-]+)}\s*(=|\+=)\s*' + quoted_string_re + '$')
# Find comma-separated groups, but allow commas that are inside quoted strings.

View File

@ -0,0 +1,50 @@
From e1bd03e75860fb349a6de589bbb1274acc454aef Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Renaud=20M=C3=A9trich?= <rmetrich@redhat.com>
Date: Fri, 13 Sep 2019 11:18:18 +0200
Subject: [PATCH] Call getgroups() to know size of supplementary groups array
to allocate
Resolves RHBZ #1743230 - journalctl dumps core when stack limit is reduced to 256 KB
(cherry picked from commit f5e0b942af1e86993c21f4e5c84342bb10403dac)
Resolves: #1743235
---
src/basic/user-util.c | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/src/basic/user-util.c b/src/basic/user-util.c
index a562a397c7..c533f67025 100644
--- a/src/basic/user-util.c
+++ b/src/basic/user-util.c
@@ -358,9 +358,8 @@ char* gid_to_name(gid_t gid) {
}
int in_gid(gid_t gid) {
- long ngroups_max;
gid_t *gids;
- int r, i;
+ int ngroups, r, i;
if (getgid() == gid)
return 1;
@@ -371,12 +370,15 @@ int in_gid(gid_t gid) {
if (!gid_is_valid(gid))
return -EINVAL;
- ngroups_max = sysconf(_SC_NGROUPS_MAX);
- assert(ngroups_max > 0);
+ ngroups = getgroups(0, NULL);
+ if (ngroups < 0)
+ return -errno;
+ if (ngroups == 0)
+ return 0;
- gids = newa(gid_t, ngroups_max);
+ gids = newa(gid_t, ngroups);
- r = getgroups(ngroups_max, gids);
+ r = getgroups(ngroups, gids);
if (r < 0)
return -errno;

View File

@ -0,0 +1,30 @@
From 1bf923686a6842f222b1ef5f5174511340c75685 Mon Sep 17 00:00:00 2001
From: Jan Synacek <jsynacek@redhat.com>
Date: Tue, 1 Oct 2019 08:45:08 +0200
Subject: [PATCH] Consider smb3 as remote filesystem
Currently systemd will treat smb3 as local filesystem and cause
can't boot failures. Add smb3 to the list of remote filesystems
to fix this issue.
Signed-off-by: Kenneth D'souza <kdsouza@redhat.com>
(cherry picked from commit ff7d6a740b0c6fa3be63d3908a0858730a0837c5)
Resolves: #1757257
---
src/basic/mount-util.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c
index 3670b7f591..5b04e21f34 100644
--- a/src/basic/mount-util.c
+++ b/src/basic/mount-util.c
@@ -603,6 +603,7 @@ bool fstype_is_network(const char *fstype) {
return STR_IN_SET(fstype,
"afs",
"cifs",
+ "smb3",
"smbfs",
"sshfs",
"ncpfs",

View File

@ -0,0 +1,114 @@
From f057aa6bb604845fa10ad569bca306e5e1e8fe0d Mon Sep 17 00:00:00 2001
From: Franck Bui <fbui@suse.com>
Date: Mon, 18 Mar 2019 11:48:34 +0100
Subject: [PATCH] process-util: introduce pid_is_my_child() helper
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
No functional changes.
Thanks Renaud Métrich for backporting this to RHEL.
Resolves: #1744972
---
src/basic/process-util.c | 14 ++++++++++++++
src/basic/process-util.h | 1 +
src/core/cgroup.c | 7 ++-----
src/core/service.c | 8 ++------
4 files changed, 19 insertions(+), 11 deletions(-)
diff --git a/src/basic/process-util.c b/src/basic/process-util.c
index aa3eff779a..6dbeee9dda 100644
--- a/src/basic/process-util.c
+++ b/src/basic/process-util.c
@@ -903,6 +903,20 @@ int getenv_for_pid(pid_t pid, const char *field, char **ret) {
return 0;
}
+int pid_is_my_child(pid_t pid) {
+ pid_t ppid;
+ int r;
+
+ if (pid <= 1)
+ return false;
+
+ r = get_process_ppid(pid, &ppid);
+ if (r < 0)
+ return r;
+
+ return ppid == getpid_cached();
+}
+
bool pid_is_unwaited(pid_t pid) {
/* Checks whether a PID is still valid at all, including a zombie */
diff --git a/src/basic/process-util.h b/src/basic/process-util.h
index a5bb072b25..a3bd2851b4 100644
--- a/src/basic/process-util.h
+++ b/src/basic/process-util.h
@@ -68,6 +68,7 @@ int getenv_for_pid(pid_t pid, const char *field, char **_value);
bool pid_is_alive(pid_t pid);
bool pid_is_unwaited(pid_t pid);
+int pid_is_my_child(pid_t pid);
int pid_from_same_root_fs(pid_t pid);
bool is_main_thread(void);
diff --git a/src/core/cgroup.c b/src/core/cgroup.c
index 62ab41a288..b7ed07e65b 100644
--- a/src/core/cgroup.c
+++ b/src/core/cgroup.c
@@ -1876,7 +1876,7 @@ void unit_prune_cgroup(Unit *u) {
int unit_search_main_pid(Unit *u, pid_t *ret) {
_cleanup_fclose_ FILE *f = NULL;
- pid_t pid = 0, npid, mypid;
+ pid_t pid = 0, npid;
int r;
assert(u);
@@ -1889,15 +1889,12 @@ int unit_search_main_pid(Unit *u, pid_t *ret) {
if (r < 0)
return r;
- mypid = getpid_cached();
while (cg_read_pid(f, &npid) > 0) {
- pid_t ppid;
if (npid == pid)
continue;
- /* Ignore processes that aren't our kids */
- if (get_process_ppid(npid, &ppid) >= 0 && ppid != mypid)
+ if (pid_is_my_child(npid) == 0)
continue;
if (pid != 0)
diff --git a/src/core/service.c b/src/core/service.c
index 24f167572a..614ba05d89 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -139,8 +139,6 @@ static void service_unwatch_pid_file(Service *s) {
}
static int service_set_main_pid(Service *s, pid_t pid) {
- pid_t ppid;
-
assert(s);
if (pid <= 1)
@@ -159,12 +157,10 @@ static int service_set_main_pid(Service *s, pid_t pid) {
s->main_pid = pid;
s->main_pid_known = true;
+ s->main_pid_alien = pid_is_my_child(pid) == 0;
- if (get_process_ppid(pid, &ppid) >= 0 && ppid != getpid_cached()) {
+ if (s->main_pid_alien)
log_unit_warning(UNIT(s), "Supervising process "PID_FMT" which is not our child. We'll most likely not notice when it exits.", pid);
- s->main_pid_alien = true;
- } else
- s->main_pid_alien = false;
return 0;
}

View File

@ -0,0 +1,323 @@
From 79e9566ec0a61d887ab63f17192dbd71aae36ee0 Mon Sep 17 00:00:00 2001
From: Franck Bui <fbui@suse.com>
Date: Mon, 18 Mar 2019 20:59:36 +0100
Subject: [PATCH] core: reduce the number of stalled PIDs from the watched
processes list when possible
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Some PIDs can remain in the watched list even though their processes have
exited since a long time. It can easily happen if the main process of a forking
service manages to spawn a child before the control process exits for example.
However when a pid is about to be mapped to a unit by calling unit_watch_pid(),
the caller usually knows if the pid should belong to this unit exclusively: if
we just forked() off a child, then we can be sure that its PID is otherwise
unused. In this case we take this opportunity to remove any stalled PIDs from
the watched process list.
If we learnt about a PID in any other form (for example via PID file, via
searching, MAINPID= and so on), then we can't assume anything.
Thanks Renaud Métrich for backporting this to RHEL.
Resolves: #1744972
---
src/core/cgroup.c | 2 +-
src/core/dbus-scope.c | 2 +-
src/core/manager.c | 10 ++++++++++
src/core/manager.h | 2 ++
src/core/mount.c | 5 ++---
src/core/service.c | 16 ++++++++--------
src/core/socket.c | 7 +++----
src/core/swap.c | 5 ++---
src/core/unit.c | 8 +++++++-
src/core/unit.h | 2 +-
src/test/test-watch-pid.c | 12 ++++++------
11 files changed, 43 insertions(+), 28 deletions(-)
diff --git a/src/core/cgroup.c b/src/core/cgroup.c
index b7ed07e65b..76eafdc082 100644
--- a/src/core/cgroup.c
+++ b/src/core/cgroup.c
@@ -1926,7 +1926,7 @@ static int unit_watch_pids_in_path(Unit *u, const char *path) {
pid_t pid;
while ((r = cg_read_pid(f, &pid)) > 0) {
- r = unit_watch_pid(u, pid);
+ r = unit_watch_pid(u, pid, false);
if (r < 0 && ret >= 0)
ret = r;
}
diff --git a/src/core/dbus-scope.c b/src/core/dbus-scope.c
index 6725f62794..0bbf64fff1 100644
--- a/src/core/dbus-scope.c
+++ b/src/core/dbus-scope.c
@@ -106,7 +106,7 @@ static int bus_scope_set_transient_property(
return r;
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
- r = unit_watch_pid(UNIT(s), pid);
+ r = unit_watch_pid(UNIT(s), pid, false);
if (r < 0 && r != -EEXIST)
return r;
}
diff --git a/src/core/manager.c b/src/core/manager.c
index c83e296cf3..0eae7d46fb 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -2044,6 +2044,16 @@ void manager_clear_jobs(Manager *m) {
job_finish_and_invalidate(j, JOB_CANCELED, false, false);
}
+void manager_unwatch_pid(Manager *m, pid_t pid) {
+ assert(m);
+
+ /* First let's drop the unit keyed as "pid". */
+ (void) hashmap_remove(m->watch_pids, PID_TO_PTR(pid));
+
+ /* Then, let's also drop the array keyed by -pid. */
+ free(hashmap_remove(m->watch_pids, PID_TO_PTR(-pid)));
+}
+
static int manager_dispatch_run_queue(sd_event_source *source, void *userdata) {
Manager *m = userdata;
Job *j;
diff --git a/src/core/manager.h b/src/core/manager.h
index c7f4d66ecd..fa47952d24 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -406,6 +406,8 @@ int manager_get_dump_string(Manager *m, char **ret);
void manager_clear_jobs(Manager *m);
+void manager_unwatch_pid(Manager *m, pid_t pid);
+
unsigned manager_dispatch_load_queue(Manager *m);
int manager_environment_add(Manager *m, char **minus, char **plus);
diff --git a/src/core/mount.c b/src/core/mount.c
index 2ac04e3874..5878814b1b 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -677,7 +677,7 @@ static int mount_coldplug(Unit *u) {
pid_is_unwaited(m->control_pid) &&
MOUNT_STATE_WITH_PROCESS(new_state)) {
- r = unit_watch_pid(UNIT(m), m->control_pid);
+ r = unit_watch_pid(UNIT(m), m->control_pid, false);
if (r < 0)
return r;
@@ -781,9 +781,8 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
if (r < 0)
return r;
- r = unit_watch_pid(UNIT(m), pid);
+ r = unit_watch_pid(UNIT(m), pid, true);
if (r < 0)
- /* FIXME: we need to do something here */
return r;
*_pid = pid;
diff --git a/src/core/service.c b/src/core/service.c
index 614ba05d89..310838a5f6 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -974,7 +974,7 @@ static int service_load_pid_file(Service *s, bool may_warn) {
if (r < 0)
return r;
- r = unit_watch_pid(UNIT(s), pid);
+ r = unit_watch_pid(UNIT(s), pid, false);
if (r < 0) /* FIXME: we need to do something here */
return log_unit_warning_errno(UNIT(s), r, "Failed to watch PID "PID_FMT" for service: %m", pid);
@@ -1004,7 +1004,7 @@ static void service_search_main_pid(Service *s) {
if (service_set_main_pid(s, pid) < 0)
return;
- r = unit_watch_pid(UNIT(s), pid);
+ r = unit_watch_pid(UNIT(s), pid, false);
if (r < 0)
/* FIXME: we need to do something here */
log_unit_warning_errno(UNIT(s), r, "Failed to watch PID "PID_FMT" from: %m", pid);
@@ -1135,7 +1135,7 @@ static int service_coldplug(Unit *u) {
SERVICE_RUNNING, SERVICE_RELOAD,
SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL))) {
- r = unit_watch_pid(UNIT(s), s->main_pid);
+ r = unit_watch_pid(UNIT(s), s->main_pid, false);
if (r < 0)
return r;
}
@@ -1147,7 +1147,7 @@ static int service_coldplug(Unit *u) {
SERVICE_RELOAD,
SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) {
- r = unit_watch_pid(UNIT(s), s->control_pid);
+ r = unit_watch_pid(UNIT(s), s->control_pid, false);
if (r < 0)
return r;
}
@@ -1545,8 +1545,8 @@ static int service_spawn(
s->exec_fd_event_source = TAKE_PTR(exec_fd_source);
s->exec_fd_hot = false;
- r = unit_watch_pid(UNIT(s), pid);
- if (r < 0) /* FIXME: we need to do something here */
+ r = unit_watch_pid(UNIT(s), pid, true);
+ if (r < 0)
return r;
*_pid = pid;
@@ -3643,7 +3643,7 @@ static void service_notify_message(
}
if (r > 0) {
service_set_main_pid(s, new_main_pid);
- unit_watch_pid(UNIT(s), new_main_pid);
+ unit_watch_pid(UNIT(s), new_main_pid, false);
notify_dbus = true;
}
}
@@ -3858,7 +3858,7 @@ static void service_bus_name_owner_change(
log_unit_debug(u, "D-Bus name %s is now owned by process " PID_FMT, name, pid);
service_set_main_pid(s, pid);
- unit_watch_pid(UNIT(s), pid);
+ unit_watch_pid(UNIT(s), pid, false);
}
}
}
diff --git a/src/core/socket.c b/src/core/socket.c
index d488c64e91..b034549634 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -1816,7 +1816,7 @@ static int socket_coldplug(Unit *u) {
SOCKET_FINAL_SIGTERM,
SOCKET_FINAL_SIGKILL)) {
- r = unit_watch_pid(UNIT(s), s->control_pid);
+ r = unit_watch_pid(UNIT(s), s->control_pid, false);
if (r < 0)
return r;
@@ -1902,9 +1902,8 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
if (r < 0)
return r;
- r = unit_watch_pid(UNIT(s), pid);
+ r = unit_watch_pid(UNIT(s), pid, true);
if (r < 0)
- /* FIXME: we need to do something here */
return r;
*_pid = pid;
@@ -1973,7 +1972,7 @@ static int socket_chown(Socket *s, pid_t *_pid) {
_exit(EXIT_SUCCESS);
}
- r = unit_watch_pid(UNIT(s), pid);
+ r = unit_watch_pid(UNIT(s), pid, true);
if (r < 0)
goto fail;
diff --git a/src/core/swap.c b/src/core/swap.c
index b644753a1c..e717dbb54a 100644
--- a/src/core/swap.c
+++ b/src/core/swap.c
@@ -531,7 +531,7 @@ static int swap_coldplug(Unit *u) {
pid_is_unwaited(s->control_pid) &&
SWAP_STATE_WITH_PROCESS(new_state)) {
- r = unit_watch_pid(UNIT(s), s->control_pid);
+ r = unit_watch_pid(UNIT(s), s->control_pid, false);
if (r < 0)
return r;
@@ -636,9 +636,8 @@ static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) {
if (r < 0)
goto fail;
- r = unit_watch_pid(UNIT(s), pid);
+ r = unit_watch_pid(UNIT(s), pid, true);
if (r < 0)
- /* FIXME: we need to do something here */
goto fail;
*_pid = pid;
diff --git a/src/core/unit.c b/src/core/unit.c
index d298afb0d4..b0b1c77ef7 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -2500,7 +2500,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, UnitNotifyFlag
unit_add_to_gc_queue(u);
}
-int unit_watch_pid(Unit *u, pid_t pid) {
+int unit_watch_pid(Unit *u, pid_t pid, bool exclusive) {
int r;
assert(u);
@@ -2508,6 +2508,12 @@ int unit_watch_pid(Unit *u, pid_t pid) {
/* Watch a specific PID */
+ /* Caller might be sure that this PID belongs to this unit only. Let's take this
+ * opportunity to remove any stalled references to this PID as they can be created
+ * easily (when watching a process which is not our direct child). */
+ if (exclusive)
+ manager_unwatch_pid(u->manager, pid);
+
r = set_ensure_allocated(&u->pids, NULL);
if (r < 0)
return r;
diff --git a/src/core/unit.h b/src/core/unit.h
index e1a60da244..68cc1869e4 100644
--- a/src/core/unit.h
+++ b/src/core/unit.h
@@ -655,7 +655,7 @@ typedef enum UnitNotifyFlags {
void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, UnitNotifyFlags flags);
-int unit_watch_pid(Unit *u, pid_t pid);
+int unit_watch_pid(Unit *u, pid_t pid, bool exclusive);
void unit_unwatch_pid(Unit *u, pid_t pid);
void unit_unwatch_all_pids(Unit *u);
diff --git a/src/test/test-watch-pid.c b/src/test/test-watch-pid.c
index cb43b35bc5..8c70175aed 100644
--- a/src/test/test-watch-pid.c
+++ b/src/test/test-watch-pid.c
@@ -49,25 +49,25 @@ int main(int argc, char *argv[]) {
assert_se(hashmap_isempty(m->watch_pids));
assert_se(manager_get_unit_by_pid(m, 4711) == NULL);
- assert_se(unit_watch_pid(a, 4711) >= 0);
+ assert_se(unit_watch_pid(a, 4711, false) >= 0);
assert_se(manager_get_unit_by_pid(m, 4711) == a);
- assert_se(unit_watch_pid(a, 4711) >= 0);
+ assert_se(unit_watch_pid(a, 4711, false) >= 0);
assert_se(manager_get_unit_by_pid(m, 4711) == a);
- assert_se(unit_watch_pid(b, 4711) >= 0);
+ assert_se(unit_watch_pid(b, 4711, false) >= 0);
u = manager_get_unit_by_pid(m, 4711);
assert_se(u == a || u == b);
- assert_se(unit_watch_pid(b, 4711) >= 0);
+ assert_se(unit_watch_pid(b, 4711, false) >= 0);
u = manager_get_unit_by_pid(m, 4711);
assert_se(u == a || u == b);
- assert_se(unit_watch_pid(c, 4711) >= 0);
+ assert_se(unit_watch_pid(c, 4711, false) >= 0);
u = manager_get_unit_by_pid(m, 4711);
assert_se(u == a || u == b || u == c);
- assert_se(unit_watch_pid(c, 4711) >= 0);
+ assert_se(unit_watch_pid(c, 4711, false) >= 0);
u = manager_get_unit_by_pid(m, 4711);
assert_se(u == a || u == b || u == c);

View File

@ -0,0 +1,55 @@
From 25b93538eba0275d35ef4b0792c2cd63d63d5e8d Mon Sep 17 00:00:00 2001
From: Franck Bui <fbui@suse.com>
Date: Tue, 19 Mar 2019 10:59:26 +0100
Subject: [PATCH] core: only watch processes when it's really necessary
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
If we know that main pid is our child then it's unnecessary to watch all
other processes of a unit since in this case we will get SIGCHLD when the main
process will exit and will act upon accordingly.
So let's watch all processes only if the main process is not our child since in
this case we need to detect when the cgroup will become empty in order to
figure out when the service becomes dead. This is only needed by cgroupv1.
Thanks Renaud Métrich for backporting this to RHEL.
Resolves: #1744972
---
src/core/service.c | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)
diff --git a/src/core/service.c b/src/core/service.c
index 310838a5f6..b1ec52d220 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -3410,8 +3410,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
if (main_pid_good(s) <= 0)
service_enter_stop_post(s, f);
- /* If there is still a service
- * process around, wait until
+ /* If there is still a service process around, wait until
* that one quit, too */
break;
@@ -3433,10 +3432,14 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
if (notify_dbus)
unit_add_to_dbus_queue(u);
- /* If we get a SIGCHLD event for one of the processes we were interested in, then we look for others to watch,
- * under the assumption that we'll sooner or later get a SIGCHLD for them, as the original process we watched
- * was probably the parent of them, and they are hence now our children. */
- (void) unit_enqueue_rewatch_pids(u);
+ /* We watch the main/control process otherwise we can't retrieve the unit they
+ * belong to with cgroupv1. But if they are not our direct child, we won't get a
+ * SIGCHLD for them. Therefore we need to look for others to watch so we can
+ * detect when the cgroup becomes empty. Note that the control process is always
+ * our child so it's pointless to watch all other processes. */
+ if (!control_pid_good(s))
+ if (!s->main_pid_known || s->main_pid_alien)
+ (void) unit_enqueue_rewatch_pids(u);
}
static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) {

View File

@ -0,0 +1,641 @@
From a26f2b2732733aa361fec0a3a8f0ba377f48e75c Mon Sep 17 00:00:00 2001
From: Anita Zhang <anitzhang@gmail.com>
Date: Sun, 7 Oct 2018 20:28:36 -0700
Subject: [PATCH] core: implement per unit journal rate limiting
Add LogRateLimitIntervalSec= and LogRateLimitBurst= options for
services. If provided, these values get passed to the journald
client context, and those values are used in the rate limiting
function in the journal over the the journald.conf values.
Part of #10230
(cherry picked from commit 90fc172e191f44979005a524521112f2bd1ff21b)
Resolves: #1719577
---
catalog/systemd.catalog.in | 3 +-
doc/TRANSIENT-SETTINGS.md | 2 +
man/journald.conf.xml | 8 +-
man/systemd.exec.xml | 16 ++++
src/core/dbus-execute.c | 8 ++
src/core/execute.c | 14 ++++
src/core/execute.h | 3 +
src/core/load-fragment-gperf.gperf.m4 | 2 +
src/core/unit.c | 92 +++++++++++++++++++++
src/core/unit.h | 2 +
src/journal/journald-context.c | 50 ++++++++++-
src/journal/journald-context.h | 3 +
src/journal/journald-rate-limit.c | 38 ++++-----
src/journal/journald-rate-limit.h | 4 +-
src/journal/journald-server.c | 4 +-
src/shared/bus-unit-util.c | 8 ++
test/fuzz/fuzz-unit-file/directives.service | 2 +
17 files changed, 231 insertions(+), 28 deletions(-)
diff --git a/catalog/systemd.catalog.in b/catalog/systemd.catalog.in
index f1bddc6f7d..8234e387cf 100644
--- a/catalog/systemd.catalog.in
+++ b/catalog/systemd.catalog.in
@@ -52,7 +52,8 @@ dropped, other services' messages are unaffected.
The limits controlling when messages are dropped may be configured
with RateLimitIntervalSec= and RateLimitBurst= in
-/etc/systemd/journald.conf. See journald.conf(5) for details.
+/etc/systemd/journald.conf or LogRateLimitIntervalSec= and LogRateLimitBurst=
+in the unit file. See journald.conf(5) and systemd.exec(5) for details.
-- e9bf28e6e834481bb6f48f548ad13606
Subject: Journal messages have been missed
diff --git a/doc/TRANSIENT-SETTINGS.md b/doc/TRANSIENT-SETTINGS.md
index ca9e8387b7..0ea444b133 100644
--- a/doc/TRANSIENT-SETTINGS.md
+++ b/doc/TRANSIENT-SETTINGS.md
@@ -135,6 +135,8 @@ All execution-related settings are available for transient units.
✓ SyslogLevelPrefix=
✓ LogLevelMax=
✓ LogExtraFields=
+✓ LogRateLimitIntervalSec=
+✓ LogRateLimitBurst=
✓ SecureBits=
✓ CapabilityBoundingSet=
✓ AmbientCapabilities=
diff --git a/man/journald.conf.xml b/man/journald.conf.xml
index ee8e8b7faf..b57a244b22 100644
--- a/man/journald.conf.xml
+++ b/man/journald.conf.xml
@@ -140,7 +140,13 @@
following units: <literal>s</literal>, <literal>min</literal>,
<literal>h</literal>, <literal>ms</literal>,
<literal>us</literal>. To turn off any kind of rate limiting,
- set either value to 0.</para></listitem>
+ set either value to 0.</para>
+
+ <para>If a service provides rate limits for itself through
+ <varname>LogRateLimitIntervalSec=</varname> and/or <varname>LogRateLimitBurst=</varname>
+ in <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+ those values will override the settings specified here.</para>
+ </listitem>
</varlistentry>
<varlistentry>
diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml
index 3bd790b485..737c52bcc4 100644
--- a/man/systemd.exec.xml
+++ b/man/systemd.exec.xml
@@ -1905,6 +1905,22 @@ StandardInputData=SWNrIHNpdHplIGRhIHVuJyBlc3NlIEtsb3BzLAp1ZmYgZWVtYWwga2xvcHAncy
matching. Assign an empty string to reset the list.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>LogRateLimitIntervalSec=</varname></term>
+ <term><varname>LogRateLimitBurst=</varname></term>
+
+ <listitem><para>Configures the rate limiting that is applied to messages generated by this unit. If, in the
+ time interval defined by <varname>LogRateLimitIntervalSec=</varname>, more messages than specified in
+ <varname>LogRateLimitBurst=</varname> are logged by a service, all further messages within the interval are
+ dropped until the interval is over. A message about the number of dropped messages is generated. The time
+ specification for <varname>LogRateLimitIntervalSec=</varname> may be specified in the following units: "s",
+ "min", "h", "ms", "us" (see
+ <citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry> for details).
+ The default settings are set by <varname>RateLimitIntervalSec=</varname> and <varname>RateLimitBurst=</varname>
+ configured in <citerefentry><refentrytitle>journald.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+ </para></listitem>
+ </varlistentry>
+
<varlistentry>
<term><varname>SyslogIdentifier=</varname></term>
diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
index c44970c10c..33a91c012e 100644
--- a/src/core/dbus-execute.c
+++ b/src/core/dbus-execute.c
@@ -718,6 +718,8 @@ const sd_bus_vtable bus_exec_vtable[] = {
SD_BUS_PROPERTY("SyslogLevel", "i", property_get_syslog_level, offsetof(ExecContext, syslog_priority), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SyslogFacility", "i", property_get_syslog_facility, offsetof(ExecContext, syslog_priority), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("LogLevelMax", "i", bus_property_get_int, offsetof(ExecContext, log_level_max), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LogRateLimitIntervalUSec", "t", bus_property_get_usec, offsetof(ExecContext, log_rate_limit_interval_usec), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LogRateLimitBurst", "u", bus_property_get_unsigned, offsetof(ExecContext, log_rate_limit_burst), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("LogExtraFields", "aay", property_get_log_extra_fields, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SecureBits", "i", bus_property_get_int, offsetof(ExecContext, secure_bits), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("CapabilityBoundingSet", "t", NULL, offsetof(ExecContext, capability_bounding_set), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -1073,6 +1075,12 @@ int bus_exec_context_set_transient_property(
if (streq(name, "CPUSchedulingPriority"))
return bus_set_transient_sched_priority(u, name, &c->cpu_sched_priority, message, flags, error);
+ if (streq(name, "LogRateLimitIntervalUSec"))
+ return bus_set_transient_usec(u, name, &c->log_rate_limit_interval_usec, message, flags, error);
+
+ if (streq(name, "LogRateLimitBurst"))
+ return bus_set_transient_unsigned(u, name, &c->log_rate_limit_burst, message, flags, error);
+
if (streq(name, "Personality"))
return bus_set_transient_personality(u, name, &c->personality, message, flags, error);
diff --git a/src/core/execute.c b/src/core/execute.c
index c62f3cf849..8293c522bc 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -3693,6 +3693,9 @@ void exec_context_done(ExecContext *c) {
exec_context_free_log_extra_fields(c);
+ c->log_rate_limit_interval_usec = 0;
+ c->log_rate_limit_burst = 0;
+
c->stdin_data = mfree(c->stdin_data);
c->stdin_data_size = 0;
}
@@ -4153,6 +4156,17 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
fprintf(f, "%sLogLevelMax: %s\n", prefix, strna(t));
}
+ if (c->log_rate_limit_interval_usec > 0) {
+ char buf_timespan[FORMAT_TIMESPAN_MAX];
+
+ fprintf(f,
+ "%sLogRateLimitIntervalSec: %s\n",
+ prefix, format_timespan(buf_timespan, sizeof(buf_timespan), c->log_rate_limit_interval_usec, USEC_PER_SEC));
+ }
+
+ if (c->log_rate_limit_burst > 0)
+ fprintf(f, "%sLogRateLimitBurst: %u\n", prefix, c->log_rate_limit_burst);
+
if (c->n_log_extra_fields > 0) {
size_t j;
diff --git a/src/core/execute.h b/src/core/execute.h
index bff1634b88..8c91636adc 100644
--- a/src/core/execute.h
+++ b/src/core/execute.h
@@ -216,6 +216,9 @@ struct ExecContext {
struct iovec* log_extra_fields;
size_t n_log_extra_fields;
+ usec_t log_rate_limit_interval_usec;
+ unsigned log_rate_limit_burst;
+
bool cpu_sched_reset_on_fork;
bool non_blocking;
bool private_tmp;
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
index 15fb47838c..1066bcfb8f 100644
--- a/src/core/load-fragment-gperf.gperf.m4
+++ b/src/core/load-fragment-gperf.gperf.m4
@@ -57,6 +57,8 @@ $1.SyslogFacility, config_parse_log_facility, 0,
$1.SyslogLevel, config_parse_log_level, 0, offsetof($1, exec_context.syslog_priority)
$1.SyslogLevelPrefix, config_parse_bool, 0, offsetof($1, exec_context.syslog_level_prefix)
$1.LogLevelMax, config_parse_log_level, 0, offsetof($1, exec_context.log_level_max)
+$1.LogRateLimitIntervalSec, config_parse_sec, 0, offsetof($1, exec_context.log_rate_limit_interval_usec)
+$1.LogRateLimitBurst, config_parse_unsigned, 0, offsetof($1, exec_context.log_rate_limit_burst)
$1.LogExtraFields, config_parse_log_extra_fields, 0, offsetof($1, exec_context)
$1.Capabilities, config_parse_warn_compat, DISABLED_LEGACY, offsetof($1, exec_context)
$1.SecureBits, config_parse_exec_secure_bits, 0, offsetof($1, exec_context.secure_bits)
diff --git a/src/core/unit.c b/src/core/unit.c
index b0b1c77ef7..115739f4c6 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -3245,6 +3245,8 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) {
unit_serialize_item(u, f, "exported-invocation-id", yes_no(u->exported_invocation_id));
unit_serialize_item(u, f, "exported-log-level-max", yes_no(u->exported_log_level_max));
unit_serialize_item(u, f, "exported-log-extra-fields", yes_no(u->exported_log_extra_fields));
+ unit_serialize_item(u, f, "exported-log-rate-limit-interval", yes_no(u->exported_log_rate_limit_interval));
+ unit_serialize_item(u, f, "exported-log-rate-limit-burst", yes_no(u->exported_log_rate_limit_burst));
unit_serialize_item_format(u, f, "cpu-usage-base", "%" PRIu64, u->cpu_usage_base);
if (u->cpu_usage_last != NSEC_INFINITY)
@@ -3508,6 +3510,26 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
continue;
+ } else if (streq(l, "exported-log-rate-limit-interval")) {
+
+ r = parse_boolean(v);
+ if (r < 0)
+ log_unit_debug(u, "Failed to parse exported log rate limit interval %s, ignoring.", v);
+ else
+ u->exported_log_rate_limit_interval = r;
+
+ continue;
+
+ } else if (streq(l, "exported-log-rate-limit-burst")) {
+
+ r = parse_boolean(v);
+ if (r < 0)
+ log_unit_debug(u, "Failed to parse exported log rate limit burst %s, ignoring.", v);
+ else
+ u->exported_log_rate_limit_burst = r;
+
+ continue;
+
} else if (STR_IN_SET(l, "cpu-usage-base", "cpuacct-usage-base")) {
r = safe_atou64(v, &u->cpu_usage_base);
@@ -5241,6 +5263,60 @@ fail:
return r;
}
+static int unit_export_log_rate_limit_interval(Unit *u, const ExecContext *c) {
+ _cleanup_free_ char *buf = NULL;
+ const char *p;
+ int r;
+
+ assert(u);
+ assert(c);
+
+ if (u->exported_log_rate_limit_interval)
+ return 0;
+
+ if (c->log_rate_limit_interval_usec == 0)
+ return 0;
+
+ p = strjoina("/run/systemd/units/log-rate-limit-interval:", u->id);
+
+ if (asprintf(&buf, "%" PRIu64, c->log_rate_limit_interval_usec) < 0)
+ return log_oom();
+
+ r = symlink_atomic(buf, p);
+ if (r < 0)
+ return log_unit_debug_errno(u, r, "Failed to create log rate limit interval symlink %s: %m", p);
+
+ u->exported_log_rate_limit_interval = true;
+ return 0;
+}
+
+static int unit_export_log_rate_limit_burst(Unit *u, const ExecContext *c) {
+ _cleanup_free_ char *buf = NULL;
+ const char *p;
+ int r;
+
+ assert(u);
+ assert(c);
+
+ if (u->exported_log_rate_limit_burst)
+ return 0;
+
+ if (c->log_rate_limit_burst == 0)
+ return 0;
+
+ p = strjoina("/run/systemd/units/log-rate-limit-burst:", u->id);
+
+ if (asprintf(&buf, "%u", c->log_rate_limit_burst) < 0)
+ return log_oom();
+
+ r = symlink_atomic(buf, p);
+ if (r < 0)
+ return log_unit_debug_errno(u, r, "Failed to create log rate limit burst symlink %s: %m", p);
+
+ u->exported_log_rate_limit_burst = true;
+ return 0;
+}
+
void unit_export_state_files(Unit *u) {
const ExecContext *c;
@@ -5274,6 +5350,8 @@ void unit_export_state_files(Unit *u) {
if (c) {
(void) unit_export_log_level_max(u, c);
(void) unit_export_log_extra_fields(u, c);
+ (void) unit_export_log_rate_limit_interval(u, c);
+ (void) unit_export_log_rate_limit_burst(u, c);
}
}
@@ -5310,6 +5388,20 @@ void unit_unlink_state_files(Unit *u) {
u->exported_log_extra_fields = false;
}
+
+ if (u->exported_log_rate_limit_interval) {
+ p = strjoina("/run/systemd/units/log-rate-limit-interval:", u->id);
+ (void) unlink(p);
+
+ u->exported_log_rate_limit_interval = false;
+ }
+
+ if (u->exported_log_rate_limit_burst) {
+ p = strjoina("/run/systemd/units/log-rate-limit-burst:", u->id);
+ (void) unlink(p);
+
+ u->exported_log_rate_limit_burst = false;
+ }
}
int unit_prepare_exec(Unit *u) {
diff --git a/src/core/unit.h b/src/core/unit.h
index 68cc1869e4..99755823eb 100644
--- a/src/core/unit.h
+++ b/src/core/unit.h
@@ -349,6 +349,8 @@ typedef struct Unit {
bool exported_invocation_id:1;
bool exported_log_level_max:1;
bool exported_log_extra_fields:1;
+ bool exported_log_rate_limit_interval:1;
+ bool exported_log_rate_limit_burst:1;
/* When writing transient unit files, stores which section we stored last. If < 0, we didn't write any yet. If
* == 0 we are in the [Unit] section, if > 0 we are in the unit type-specific section. */
diff --git a/src/journal/journald-context.c b/src/journal/journald-context.c
index dba3525ed8..c8e97e16de 100644
--- a/src/journal/journald-context.c
+++ b/src/journal/journald-context.c
@@ -140,6 +140,8 @@ static int client_context_new(Server *s, pid_t pid, ClientContext **ret) {
c->timestamp = USEC_INFINITY;
c->extra_fields_mtime = NSEC_INFINITY;
c->log_level_max = -1;
+ c->log_rate_limit_interval = s->rate_limit_interval;
+ c->log_rate_limit_burst = s->rate_limit_burst;
r = hashmap_put(s->client_contexts, PID_TO_PTR(pid), c);
if (r < 0) {
@@ -151,7 +153,8 @@ static int client_context_new(Server *s, pid_t pid, ClientContext **ret) {
return 0;
}
-static void client_context_reset(ClientContext *c) {
+static void client_context_reset(Server *s, ClientContext *c) {
+ assert(s);
assert(c);
c->timestamp = USEC_INFINITY;
@@ -186,6 +189,9 @@ static void client_context_reset(ClientContext *c) {
c->extra_fields_mtime = NSEC_INFINITY;
c->log_level_max = -1;
+
+ c->log_rate_limit_interval = s->rate_limit_interval;
+ c->log_rate_limit_burst = s->rate_limit_burst;
}
static ClientContext* client_context_free(Server *s, ClientContext *c) {
@@ -199,7 +205,7 @@ static ClientContext* client_context_free(Server *s, ClientContext *c) {
if (c->in_lru)
assert_se(prioq_remove(s->client_contexts_lru, c, &c->lru_index) >= 0);
- client_context_reset(c);
+ client_context_reset(s, c);
return mfree(c);
}
@@ -464,6 +470,42 @@ static int client_context_read_extra_fields(
return 0;
}
+static int client_context_read_log_rate_limit_interval(ClientContext *c) {
+ _cleanup_free_ char *value = NULL;
+ const char *p;
+ int r;
+
+ assert(c);
+
+ if (!c->unit)
+ return 0;
+
+ p = strjoina("/run/systemd/units/log-rate-limit-interval:", c->unit);
+ r = readlink_malloc(p, &value);
+ if (r < 0)
+ return r;
+
+ return safe_atou64(value, &c->log_rate_limit_interval);
+}
+
+static int client_context_read_log_rate_limit_burst(ClientContext *c) {
+ _cleanup_free_ char *value = NULL;
+ const char *p;
+ int r;
+
+ assert(c);
+
+ if (!c->unit)
+ return 0;
+
+ p = strjoina("/run/systemd/units/log-rate-limit-burst:", c->unit);
+ r = readlink_malloc(p, &value);
+ if (r < 0)
+ return r;
+
+ return safe_atou(value, &c->log_rate_limit_burst);
+}
+
static void client_context_really_refresh(
Server *s,
ClientContext *c,
@@ -490,6 +532,8 @@ static void client_context_really_refresh(
(void) client_context_read_invocation_id(s, c);
(void) client_context_read_log_level_max(s, c);
(void) client_context_read_extra_fields(s, c);
+ (void) client_context_read_log_rate_limit_interval(c);
+ (void) client_context_read_log_rate_limit_burst(c);
c->timestamp = timestamp;
@@ -520,7 +564,7 @@ void client_context_maybe_refresh(
/* If the data isn't pinned and if the cashed data is older than the upper limit, we flush it out
* entirely. This follows the logic that as long as an entry is pinned the PID reuse is unlikely. */
if (c->n_ref == 0 && c->timestamp + MAX_USEC < timestamp) {
- client_context_reset(c);
+ client_context_reset(s, c);
goto refresh;
}
diff --git a/src/journal/journald-context.h b/src/journal/journald-context.h
index 9df3a38eff..5e19c71f14 100644
--- a/src/journal/journald-context.h
+++ b/src/journal/journald-context.h
@@ -49,6 +49,9 @@ struct ClientContext {
size_t extra_fields_n_iovec;
void *extra_fields_data;
nsec_t extra_fields_mtime;
+
+ usec_t log_rate_limit_interval;
+ unsigned log_rate_limit_burst;
};
int client_context_get(
diff --git a/src/journal/journald-rate-limit.c b/src/journal/journald-rate-limit.c
index 6a8a36a736..539efb8669 100644
--- a/src/journal/journald-rate-limit.c
+++ b/src/journal/journald-rate-limit.c
@@ -39,6 +39,10 @@ struct JournalRateLimitGroup {
JournalRateLimit *parent;
char *id;
+
+ /* Interval is stored to keep track of when the group expires */
+ usec_t interval;
+
JournalRateLimitPool pools[POOLS_MAX];
uint64_t hash;
@@ -47,8 +51,6 @@ struct JournalRateLimitGroup {
};
struct JournalRateLimit {
- usec_t interval;
- unsigned burst;
JournalRateLimitGroup* buckets[BUCKETS_MAX];
JournalRateLimitGroup *lru, *lru_tail;
@@ -58,18 +60,13 @@ struct JournalRateLimit {
uint8_t hash_key[16];
};
-JournalRateLimit *journal_rate_limit_new(usec_t interval, unsigned burst) {
+JournalRateLimit *journal_rate_limit_new(void) {
JournalRateLimit *r;
- assert(interval > 0 || burst == 0);
-
r = new0(JournalRateLimit, 1);
if (!r)
return NULL;
- r->interval = interval;
- r->burst = burst;
-
random_bytes(r->hash_key, sizeof(r->hash_key));
return r;
@@ -109,7 +106,7 @@ _pure_ static bool journal_rate_limit_group_expired(JournalRateLimitGroup *g, us
assert(g);
for (i = 0; i < POOLS_MAX; i++)
- if (g->pools[i].begin + g->parent->interval >= ts)
+ if (g->pools[i].begin + g->interval >= ts)
return false;
return true;
@@ -126,7 +123,7 @@ static void journal_rate_limit_vacuum(JournalRateLimit *r, usec_t ts) {
journal_rate_limit_group_free(r->lru_tail);
}
-static JournalRateLimitGroup* journal_rate_limit_group_new(JournalRateLimit *r, const char *id, usec_t ts) {
+static JournalRateLimitGroup* journal_rate_limit_group_new(JournalRateLimit *r, const char *id, usec_t interval, usec_t ts) {
JournalRateLimitGroup *g;
struct siphash state;
@@ -145,6 +142,8 @@ static JournalRateLimitGroup* journal_rate_limit_group_new(JournalRateLimit *r,
string_hash_func(g->id, &state);
g->hash = siphash24_finalize(&state);
+ g->interval = interval;
+
journal_rate_limit_vacuum(r, ts);
LIST_PREPEND(bucket, r->buckets[g->hash % BUCKETS_MAX], g);
@@ -189,7 +188,7 @@ static unsigned burst_modulate(unsigned burst, uint64_t available) {
return burst;
}
-int journal_rate_limit_test(JournalRateLimit *r, const char *id, int priority, uint64_t available) {
+int journal_rate_limit_test(JournalRateLimit *r, const char *id, usec_t rl_interval, unsigned rl_burst, int priority, uint64_t available) {
uint64_t h;
JournalRateLimitGroup *g;
JournalRateLimitPool *p;
@@ -209,11 +208,6 @@ int journal_rate_limit_test(JournalRateLimit *r, const char *id, int priority, u
if (!r)
return 1;
- if (r->interval == 0 || r->burst == 0)
- return 1;
-
- burst = burst_modulate(r->burst, available);
-
ts = now(CLOCK_MONOTONIC);
siphash24_init(&state, r->hash_key);
@@ -226,10 +220,16 @@ int journal_rate_limit_test(JournalRateLimit *r, const char *id, int priority, u
break;
if (!g) {
- g = journal_rate_limit_group_new(r, id, ts);
+ g = journal_rate_limit_group_new(r, id, rl_interval, ts);
if (!g)
return -ENOMEM;
- }
+ } else
+ g->interval = rl_interval;
+
+ if (rl_interval == 0 || rl_burst == 0)
+ return 1;
+
+ burst = burst_modulate(rl_burst, available);
p = &g->pools[priority_map[priority]];
@@ -240,7 +240,7 @@ int journal_rate_limit_test(JournalRateLimit *r, const char *id, int priority, u
return 1;
}
- if (p->begin + r->interval < ts) {
+ if (p->begin + rl_interval < ts) {
unsigned s;
s = p->suppressed;
diff --git a/src/journal/journald-rate-limit.h b/src/journal/journald-rate-limit.h
index 3a7f106de0..a2992800fe 100644
--- a/src/journal/journald-rate-limit.h
+++ b/src/journal/journald-rate-limit.h
@@ -5,6 +5,6 @@
typedef struct JournalRateLimit JournalRateLimit;
-JournalRateLimit *journal_rate_limit_new(usec_t interval, unsigned burst);
+JournalRateLimit *journal_rate_limit_new(void);
void journal_rate_limit_free(JournalRateLimit *r);
-int journal_rate_limit_test(JournalRateLimit *r, const char *id, int priority, uint64_t available);
+int journal_rate_limit_test(JournalRateLimit *r, const char *id, usec_t rl_interval, unsigned rl_burst, int priority, uint64_t available);
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
index 8de45552f6..0c983e102a 100644
--- a/src/journal/journald-server.c
+++ b/src/journal/journald-server.c
@@ -943,7 +943,7 @@ void server_dispatch_message(
if (c && c->unit) {
(void) determine_space(s, &available, NULL);
- rl = journal_rate_limit_test(s->rate_limit, c->unit, priority & LOG_PRIMASK, available);
+ rl = journal_rate_limit_test(s->rate_limit, c->unit, c->log_rate_limit_interval, c->log_rate_limit_burst, priority & LOG_PRIMASK, available);
if (rl == 0)
return;
@@ -1852,7 +1852,7 @@ int server_init(Server *s) {
if (!s->udev)
return -ENOMEM;
- s->rate_limit = journal_rate_limit_new(s->rate_limit_interval, s->rate_limit_burst);
+ s->rate_limit = journal_rate_limit_new();
if (!s->rate_limit)
return -ENOMEM;
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
index 3238b442c0..271cc054da 100644
--- a/src/shared/bus-unit-util.c
+++ b/src/shared/bus-unit-util.c
@@ -755,6 +755,14 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
return bus_append_parse_nsec(m, field, eq);
+ if (STR_IN_SET(field, "LogRateLimitIntervalSec"))
+
+ return bus_append_parse_sec_rename(m, field, eq);
+
+ if (streq(field, "LogRateLimitBurst"))
+
+ return bus_append_safe_atou(m, field, eq);
+
if (streq(field, "MountFlags"))
return bus_append_mount_propagation_flags_from_string(m, field, eq);
diff --git a/test/fuzz/fuzz-unit-file/directives.service b/test/fuzz/fuzz-unit-file/directives.service
index c2334d3b19..d8d1fc68b8 100644
--- a/test/fuzz/fuzz-unit-file/directives.service
+++ b/test/fuzz/fuzz-unit-file/directives.service
@@ -792,6 +792,8 @@ LineMax=
LockPersonality=
LogExtraFields=
LogLevelMax=
+LogRateLimitIntervalSec=
+LogRateLimitBurst=
LogsDirectory=
LogsDirectoryMode=
MACVLAN=

View File

@ -0,0 +1,35 @@
From 55d9d6dfb731d2f1c8c940fb8a7ea0af6c498c4c Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Mon, 9 Sep 2019 14:38:35 +0200
Subject: [PATCH] path: stop watching path specs once we triggered the target
unit
We start watching them again once we get a notification that triggered
unit entered inactive or failed state.
Fixes: #10503
(cherry picked from commit 8fca6944c2ee20c63d62154c8badddc77170b176)
Resolves: #1763161
---
src/core/path.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/src/core/path.c b/src/core/path.c
index 68b13b610a..5ef178a46b 100644
--- a/src/core/path.c
+++ b/src/core/path.c
@@ -478,11 +478,9 @@ static void path_enter_running(Path *p) {
p->inotify_triggered = false;
- r = path_watch(p);
- if (r < 0)
- goto fail;
-
path_set_state(p, PATH_RUNNING);
+ path_unwatch(p);
+
return;
fail:

View File

@ -0,0 +1,28 @@
From 33aa231f5bf3335cdacfb38ffba757865019ce4d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Renaud=20M=C3=A9trich?=
<1163635+rmetrich@users.noreply.github.com>
Date: Mon, 3 Sep 2018 05:42:39 +0200
Subject: [PATCH] journald: fixed assertion failure when system journal
rotation fails (#9893)
(cherry picked from commit fd790d6f09b10a87b007b71403cb018f18ff91c9)
Resolves: #1763619
---
src/journal/journald-server.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
index 0c983e102a..6aecb67d6c 100644
--- a/src/journal/journald-server.c
+++ b/src/journal/journald-server.c
@@ -1041,7 +1041,8 @@ int server_flush_to_var(Server *s, bool require_flag_file) {
r = 0;
finish:
- journal_file_post_change(s->system_journal);
+ if (s->system_journal)
+ journal_file_post_change(s->system_journal);
s->runtime_journal = journal_file_close(s->runtime_journal);

View File

@ -0,0 +1,29 @@
From a7f18f9ef4abc7e0732d1710ead2a18a38c3ec6d Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Fri, 15 Mar 2019 10:05:33 +0100
Subject: [PATCH] test: use PBKDF2 instead of Argon2 in cryptsetup...
to reduce memory requirements for volume manipulation. Also,
to further improve the test performance, reduce number of PBKDF
iterations to 1000 (allowed minimum).
(cherry picked from commit 5b69d297c153478f6f5e74ba66e1f4e5b6422baf)
Related: #1761519
---
test/TEST-02-CRYPTSETUP/test.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/TEST-02-CRYPTSETUP/test.sh b/test/TEST-02-CRYPTSETUP/test.sh
index 545602e17a..c38e56f72e 100755
--- a/test/TEST-02-CRYPTSETUP/test.sh
+++ b/test/TEST-02-CRYPTSETUP/test.sh
@@ -29,7 +29,7 @@ check_result_qemu() {
test_setup() {
create_empty_image
echo -n test >$TESTDIR/keyfile
- cryptsetup -q luksFormat ${LOOPDEV}p2 $TESTDIR/keyfile
+ cryptsetup -q luksFormat --pbkdf pbkdf2 --pbkdf-force-iterations 1000 ${LOOPDEV}p2 $TESTDIR/keyfile
cryptsetup luksOpen ${LOOPDEV}p2 varcrypt <$TESTDIR/keyfile
mkfs.ext4 -L var /dev/mapper/varcrypt
mkdir -p $TESTDIR/root

View File

@ -0,0 +1,252 @@
From c748b95f5a00b6d9c46026c3d251c40437e6b64a Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Thu, 1 Nov 2018 17:26:36 +0900
Subject: [PATCH] test: mask several unnecessary services
This may make CIs run faster.
(cherry picked from commit 056ae88152a722bdbea54ff33db815d585c8b9c6)
Related: #1761519
---
test/TEST-02-CRYPTSETUP/test.sh | 8 ++++++++
test/TEST-03-JOBS/test.sh | 8 ++++++++
test/TEST-04-JOURNAL/test.sh | 8 ++++++++
test/TEST-05-RLIMITS/test.sh | 8 ++++++++
test/TEST-07-ISSUE-1981/test.sh | 8 ++++++++
test/TEST-11-ISSUE-3166/test.sh | 8 ++++++++
test/TEST-12-ISSUE-3171/test.sh | 8 ++++++++
test/TEST-13-NSPAWN-SMOKE/test.sh | 8 ++++++++
test/TEST-18-FAILUREACTION/test.sh | 7 +++++++
test/TEST-19-DELEGATE/test.sh | 8 ++++++++
test/TEST-20-MAINPIDGAMES/test.sh | 8 ++++++++
test/TEST-23-TYPE-EXEC/test.sh | 8 ++++++++
12 files changed, 95 insertions(+)
diff --git a/test/TEST-02-CRYPTSETUP/test.sh b/test/TEST-02-CRYPTSETUP/test.sh
index c38e56f72e..97eb2f409e 100755
--- a/test/TEST-02-CRYPTSETUP/test.sh
+++ b/test/TEST-02-CRYPTSETUP/test.sh
@@ -45,6 +45,14 @@ test_setup() {
setup_basic_environment
+ # mask some services that we do not want to run in these tests
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-hwdb-update.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-journal-catalog-update.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-networkd.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-networkd.socket
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-resolved.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-machined.service
+
# setup the testsuite service
cat >$initdir/etc/systemd/system/testsuite.service <<EOF
[Unit]
diff --git a/test/TEST-03-JOBS/test.sh b/test/TEST-03-JOBS/test.sh
index 08e5cfe6c8..93a387df59 100755
--- a/test/TEST-03-JOBS/test.sh
+++ b/test/TEST-03-JOBS/test.sh
@@ -19,6 +19,14 @@ test_setup() {
setup_basic_environment
+ # mask some services that we do not want to run in these tests
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-hwdb-update.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-journal-catalog-update.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-networkd.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-networkd.socket
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-resolved.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-machined.service
+
# setup the testsuite service
cat >$initdir/etc/systemd/system/testsuite.service <<EOF
[Unit]
diff --git a/test/TEST-04-JOURNAL/test.sh b/test/TEST-04-JOURNAL/test.sh
index 30e7b181b2..80e5fb0a73 100755
--- a/test/TEST-04-JOURNAL/test.sh
+++ b/test/TEST-04-JOURNAL/test.sh
@@ -18,6 +18,14 @@ test_setup() {
setup_basic_environment
+ # mask some services that we do not want to run in these tests
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-hwdb-update.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-journal-catalog-update.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-networkd.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-networkd.socket
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-resolved.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-machined.service
+
# setup the testsuite service
cat >$initdir/etc/systemd/system/testsuite.service <<EOF
[Unit]
diff --git a/test/TEST-05-RLIMITS/test.sh b/test/TEST-05-RLIMITS/test.sh
index a1b855c5fb..711f87f585 100755
--- a/test/TEST-05-RLIMITS/test.sh
+++ b/test/TEST-05-RLIMITS/test.sh
@@ -18,6 +18,14 @@ test_setup() {
setup_basic_environment
+ # mask some services that we do not want to run in these tests
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-hwdb-update.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-journal-catalog-update.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-networkd.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-networkd.socket
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-resolved.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-machined.service
+
cat >$initdir/etc/systemd/system.conf <<EOF
[Manager]
DefaultLimitNOFILE=10000:16384
diff --git a/test/TEST-07-ISSUE-1981/test.sh b/test/TEST-07-ISSUE-1981/test.sh
index 88d143e479..8d3ed04712 100755
--- a/test/TEST-07-ISSUE-1981/test.sh
+++ b/test/TEST-07-ISSUE-1981/test.sh
@@ -21,6 +21,14 @@ test_setup() {
setup_basic_environment
+ # mask some services that we do not want to run in these tests
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-hwdb-update.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-journal-catalog-update.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-networkd.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-networkd.socket
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-resolved.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-machined.service
+
# setup the testsuite service
cat >$initdir/etc/systemd/system/testsuite.service <<EOF
[Unit]
diff --git a/test/TEST-11-ISSUE-3166/test.sh b/test/TEST-11-ISSUE-3166/test.sh
index 8aae4d5ed9..e6e96101aa 100755
--- a/test/TEST-11-ISSUE-3166/test.sh
+++ b/test/TEST-11-ISSUE-3166/test.sh
@@ -20,6 +20,14 @@ test_setup() {
setup_basic_environment
dracut_install false touch
+ # mask some services that we do not want to run in these tests
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-hwdb-update.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-journal-catalog-update.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-networkd.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-networkd.socket
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-resolved.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-machined.service
+
# setup the testsuite service
cat >$initdir/etc/systemd/system/testsuite.service <<EOF
[Unit]
diff --git a/test/TEST-12-ISSUE-3171/test.sh b/test/TEST-12-ISSUE-3171/test.sh
index 559fa469cd..915cc21cd8 100755
--- a/test/TEST-12-ISSUE-3171/test.sh
+++ b/test/TEST-12-ISSUE-3171/test.sh
@@ -20,6 +20,14 @@ test_setup() {
setup_basic_environment
dracut_install cat mv stat nc
+ # mask some services that we do not want to run in these tests
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-hwdb-update.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-journal-catalog-update.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-networkd.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-networkd.socket
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-resolved.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-machined.service
+
# setup the testsuite service
cat >$initdir/etc/systemd/system/testsuite.service <<EOF
[Unit]
diff --git a/test/TEST-13-NSPAWN-SMOKE/test.sh b/test/TEST-13-NSPAWN-SMOKE/test.sh
index a676384bfc..cec59fa24d 100755
--- a/test/TEST-13-NSPAWN-SMOKE/test.sh
+++ b/test/TEST-13-NSPAWN-SMOKE/test.sh
@@ -20,6 +20,14 @@ test_setup() {
setup_basic_environment
dracut_install busybox chmod rmdir unshare ip sysctl
+ # mask some services that we do not want to run in these tests
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-hwdb-update.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-journal-catalog-update.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-networkd.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-networkd.socket
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-resolved.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-machined.service
+
cp create-busybox-container $initdir/
./create-busybox-container $initdir/nc-container
diff --git a/test/TEST-18-FAILUREACTION/test.sh b/test/TEST-18-FAILUREACTION/test.sh
index e48ba9bac3..783b3aac6e 100755
--- a/test/TEST-18-FAILUREACTION/test.sh
+++ b/test/TEST-18-FAILUREACTION/test.sh
@@ -35,6 +35,13 @@ EOF
) || return 1
setup_nspawn_root
+ # mask some services that we do not want to run in these tests
+ ln -s /dev/null $initdir/etc/systemd/system/systemd-hwdb-update.service
+ ln -s /dev/null $initdir/etc/systemd/system/systemd-journal-catalog-update.service
+ ln -s /dev/null $initdir/etc/systemd/system/systemd-networkd.service
+ ln -s /dev/null $initdir/etc/systemd/system/systemd-networkd.socket
+ ln -s /dev/null $initdir/etc/systemd/system/systemd-resolved.service
+
ddebug "umount $TESTDIR/root"
umount $TESTDIR/root
}
diff --git a/test/TEST-19-DELEGATE/test.sh b/test/TEST-19-DELEGATE/test.sh
index 841a29c06f..ef1d99932a 100755
--- a/test/TEST-19-DELEGATE/test.sh
+++ b/test/TEST-19-DELEGATE/test.sh
@@ -20,6 +20,14 @@ test_setup() {
setup_basic_environment
+ # mask some services that we do not want to run in these tests
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-hwdb-update.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-journal-catalog-update.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-networkd.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-networkd.socket
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-resolved.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-machined.service
+
# setup the testsuite service
cat >$initdir/etc/systemd/system/testsuite.service <<EOF
[Unit]
diff --git a/test/TEST-20-MAINPIDGAMES/test.sh b/test/TEST-20-MAINPIDGAMES/test.sh
index b14083a256..4ec8081478 100755
--- a/test/TEST-20-MAINPIDGAMES/test.sh
+++ b/test/TEST-20-MAINPIDGAMES/test.sh
@@ -17,6 +17,14 @@ test_setup() {
setup_basic_environment
+ # mask some services that we do not want to run in these tests
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-hwdb-update.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-journal-catalog-update.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-networkd.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-networkd.socket
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-resolved.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-machined.service
+
# setup the testsuite service
cat >$initdir/etc/systemd/system/testsuite.service <<EOF
[Unit]
diff --git a/test/TEST-23-TYPE-EXEC/test.sh b/test/TEST-23-TYPE-EXEC/test.sh
index bdcea239a7..2e76451f5b 100755
--- a/test/TEST-23-TYPE-EXEC/test.sh
+++ b/test/TEST-23-TYPE-EXEC/test.sh
@@ -17,6 +17,14 @@ test_setup() {
setup_basic_environment
+ # mask some services that we do not want to run in these tests
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-hwdb-update.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-journal-catalog-update.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-networkd.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-networkd.socket
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-resolved.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-machined.service
+
# setup the testsuite service
cat >$initdir/etc/systemd/system/testsuite.service <<EOF
[Unit]

View File

@ -0,0 +1,30 @@
From 27d1acaa1d4c9299db461f0f1922c573be6a52c0 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <fsumsal@redhat.com>
Date: Mon, 21 Oct 2019 18:39:39 +0200
Subject: [PATCH] test: bump the second partition's size to 50M
The former size (10M) caused systemd-journald to crash with SIGABRT when
used on a LUKS2 partition, as the LUKS2 metadata consume a significant
part of the 10M partition, thus leaving no space for the journal file
itself (relevant for TEST-02-CRYPTSETUP). This change has been present
in upstream for a while anyway.
Related: #1761519
rhel-only
---
test/test-functions | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/test-functions b/test/test-functions
index af9d16140f..fe25a501da 100644
--- a/test/test-functions
+++ b/test/test-functions
@@ -433,7 +433,7 @@ create_empty_image() {
[ -b "$LOOPDEV" ] || return 1
echo "LOOPDEV=$LOOPDEV" >> $STATEFILE
sfdisk "$LOOPDEV" <<EOF
-,390M
+,350M
,
EOF

View File

@ -0,0 +1,51 @@
From 069cf14150b55e6580cf1d482709a0e48c36ee84 Mon Sep 17 00:00:00 2001
From: Andrew Jorgensen <ajorgens@amazon.com>
Date: Wed, 25 Jul 2018 08:06:57 -0700
Subject: [PATCH] shared/sleep-config: exclude zram devices from hibernation
candidates
On a host with sufficiently large zram but with no actual swap, logind will
respond to CanHibernate() with yes. With this patch, it will correctly respond
no, unless there are other swap devices to consider.
(cherry picked from commit 411ae92b407bd7b4549b205ad754bcd0e3dfd81f)
Resolves: #1763617
---
src/shared/sleep-config.c | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/src/shared/sleep-config.c b/src/shared/sleep-config.c
index 9e4ce183d3..a1523e3f21 100644
--- a/src/shared/sleep-config.c
+++ b/src/shared/sleep-config.c
@@ -21,6 +21,7 @@
#include "log.h"
#include "macro.h"
#include "parse-util.h"
+#include "path-util.h"
#include "sleep-config.h"
#include "string-util.h"
#include "strv.h"
@@ -201,9 +202,18 @@ int find_hibernate_location(char **device, char **type, size_t *size, size_t *us
continue;
}
- if (streq(type_field, "partition") && endswith(dev_field, "\\040(deleted)")) {
- log_warning("Ignoring deleted swapfile '%s'.", dev_field);
- continue;
+ if (streq(type_field, "partition")) {
+ if (endswith(dev_field, "\\040(deleted)")) {
+ log_warning("Ignoring deleted swapfile '%s'.", dev_field);
+ continue;
+ }
+
+ const char *fn;
+ fn = path_startswith(dev_field, "/dev/");
+ if (fn && startswith(fn, "zram")) {
+ log_debug("Ignoring compressed ram swap device '%s'.", dev_field);
+ continue;
+ }
}
if (device)
*device = TAKE_PTR(dev_field);

View File

@ -0,0 +1,45 @@
From cc3c020a5f4fc577dbd2da769c22b77e37ae4e30 Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Tue, 26 Feb 2019 17:33:27 +0100
Subject: [PATCH] selinux: don't log SELINUX_INFO and SELINUX_WARNING messages
to audit
Previously we logged even info message from libselinux as USER_AVC's to
audit. For example, setting SELinux to permissive mode generated
following audit message,
time->Tue Feb 26 11:29:29 2019
type=USER_AVC msg=audit(1551198569.423:334): pid=1 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:init_t:s0 msg='avc: received setenforce notice (enforcing=0) exe="/usr/lib/systemd/systemd" sauid=0 hostname=? addr=? terminal=?'
This is unnecessary and wrong at the same time. First, kernel already
records audit event that SELinux was switched to permissive mode, also
the type of the message really shouldn't be USER_AVC.
Let's ignore SELINUX_WARNING and SELINUX_INFO and forward to audit only
USER_AVC's and errors as these two libselinux message types have clear
mapping to audit message types.
(cherry picked from commit 6227fc14c48c4c17daed4b91f61cdd4aa375790a)
Resolves: #1763612
---
src/core/selinux-access.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/core/selinux-access.c b/src/core/selinux-access.c
index 39e994afd7..ada4f8705c 100644
--- a/src/core/selinux-access.c
+++ b/src/core/selinux-access.c
@@ -112,7 +112,11 @@ _printf_(2, 3) static int log_callback(int type, const char *fmt, ...) {
va_end(ap);
if (r >= 0) {
- audit_log_user_avc_message(fd, AUDIT_USER_AVC, buf, NULL, NULL, NULL, 0);
+ if (type == SELINUX_AVC)
+ audit_log_user_avc_message(get_audit_fd(), AUDIT_USER_AVC, buf, NULL, NULL, NULL, 0);
+ else if (type == SELINUX_ERROR)
+ audit_log_user_avc_message(get_audit_fd(), AUDIT_USER_SELINUX_ERR, buf, NULL, NULL, NULL, 0);
+
return 0;
}
}

View File

@ -0,0 +1,47 @@
From 0160499e86642f159a972be0196bf7c8a1d19ea8 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Mon, 22 Oct 2018 12:04:13 +0900
Subject: [PATCH] sd-device: introduce log_device_*() macros
(cherry picked from commit b0cba0ca526ed2d86e283a0fcfebdf0a4d4bea9b)
Related: #1753369
---
src/libsystemd/sd-device/device-util.h | 27 ++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/src/libsystemd/sd-device/device-util.h b/src/libsystemd/sd-device/device-util.h
index 6dcd2645e6..448dfc63d7 100644
--- a/src/libsystemd/sd-device/device-util.h
+++ b/src/libsystemd/sd-device/device-util.h
@@ -33,3 +33,30 @@
for (device = sd_device_enumerator_get_subsystem_first(enumerator); \
device; \
device = sd_device_enumerator_get_subsystem_next(enumerator))
+
+#define log_device_full(device, level, error, ...) \
+ ({ \
+ const char *_sysname = NULL, *_subsystem = NULL; \
+ sd_device *_d = (device); \
+ int _level = (level), _error = (error); \
+ \
+ if (_d && _unlikely_(log_get_max_level() >= _level)) { \
+ (void) sd_device_get_sysname(_d, &_sysname); \
+ (void) sd_device_get_subsystem(_d, &_subsystem); \
+ } \
+ log_object_internal(_level, _error, __FILE__, __LINE__, __func__, \
+ _sysname ? "DEVICE=" : NULL, _sysname, \
+ _subsystem ? "SUBSYSTEM=" : NULL, _subsystem, ##__VA_ARGS__); \
+ })
+
+#define log_device_debug(link, ...) log_device_full(link, LOG_DEBUG, 0, ##__VA_ARGS__)
+#define log_device_info(link, ...) log_device_full(link, LOG_INFO, 0, ##__VA_ARGS__)
+#define log_device_notice(link, ...) log_device_full(link, LOG_NOTICE, 0, ##__VA_ARGS__)
+#define log_device_warning(link, ...) log_device_full(link, LOG_WARNING, 0, ##__VA_ARGS__)
+#define log_device_error(link, ...) log_device_full(link, LOG_ERR, 0, ##__VA_ARGS__)
+
+#define log_device_debug_errno(link, error, ...) log_device_full(link, LOG_DEBUG, error, ##__VA_ARGS__)
+#define log_device_info_errno(link, error, ...) log_device_full(link, LOG_INFO, error, ##__VA_ARGS__)
+#define log_device_notice_errno(link, error, ...) log_device_full(link, LOG_NOTICE, error, ##__VA_ARGS__)
+#define log_device_warning_errno(link, error, ...) log_device_full(link, LOG_WARNING, error, ##__VA_ARGS__)
+#define log_device_error_errno(link, error, ...) log_device_full(link, LOG_ERR, error, ##__VA_ARGS__)

View File

@ -0,0 +1,505 @@
From 080d3b14470f6ac59f4cfb97a4200ed18df5c260 Mon Sep 17 00:00:00 2001
From: Fabian Henneke <fabian@henneke.me>
Date: Wed, 21 Aug 2019 11:17:59 +0200
Subject: [PATCH] udev: Add id program and rule for FIDO security tokens
Add a fido_id program meant to be run for devices in the hidraw
subsystem via an IMPORT directive. The program parses the HID report
descriptor and assigns the ID_SECURITY_TOKEN environment variable if a
declared usage matches the FIDO_CTAPHID_USAGE declared in the FIDO CTAP
specification. This replaces the previous approach of whitelisting all
known security token models manually.
This commit is accompanied by a test suite and a fuzzer target for the
descriptor parsing routine.
Fixes: #11996.
(cherry picked from commit d45ee2f31a8358db0accde2e7c81777cedadc3c2)
Resolves: #1753369
---
rules/60-fido-id.rules | 7 ++
rules/meson.build | 1 +
src/fuzz/fuzz-fido-id-desc.c | 23 +++++++
src/fuzz/fuzz-fido-id-desc.dict | 6 ++
src/fuzz/meson.build | 4 ++
src/test/meson.build | 4 ++
src/test/test-fido-id-desc.c | 85 +++++++++++++++++++++++
src/udev/fido_id/fido_id.c | 103 ++++++++++++++++++++++++++++
src/udev/fido_id/fido_id_desc.c | 92 +++++++++++++++++++++++++
src/udev/fido_id/fido_id_desc.h | 8 +++
src/udev/meson.build | 3 +
test/fuzz/fuzz-fido-id-desc/crash0 | 1 +
test/fuzz/fuzz-fido-id-desc/crash1 | 1 +
test/fuzz/fuzz-fido-id-desc/report0 | Bin 0 -> 71 bytes
test/fuzz/fuzz-fido-id-desc/report1 | Bin 0 -> 34 bytes
15 files changed, 338 insertions(+)
create mode 100644 rules/60-fido-id.rules
create mode 100644 src/fuzz/fuzz-fido-id-desc.c
create mode 100644 src/fuzz/fuzz-fido-id-desc.dict
create mode 100644 src/test/test-fido-id-desc.c
create mode 100644 src/udev/fido_id/fido_id.c
create mode 100644 src/udev/fido_id/fido_id_desc.c
create mode 100644 src/udev/fido_id/fido_id_desc.h
create mode 100644 test/fuzz/fuzz-fido-id-desc/crash0
create mode 100644 test/fuzz/fuzz-fido-id-desc/crash1
create mode 100644 test/fuzz/fuzz-fido-id-desc/report0
create mode 100644 test/fuzz/fuzz-fido-id-desc/report1
diff --git a/rules/60-fido-id.rules b/rules/60-fido-id.rules
new file mode 100644
index 0000000000..fcf5079704
--- /dev/null
+++ b/rules/60-fido-id.rules
@@ -0,0 +1,7 @@
+# do not edit this file, it will be overwritten on update
+
+ACTION=="remove", GOTO="fido_id_end"
+
+SUBSYSTEM=="hidraw", IMPORT{program}="fido_id"
+
+LABEL="fido_id_end"
diff --git a/rules/meson.build b/rules/meson.build
index b6aae596b6..6363f8bf2e 100644
--- a/rules/meson.build
+++ b/rules/meson.build
@@ -7,6 +7,7 @@ rules = files('''
60-cdrom_id.rules
60-drm.rules
60-evdev.rules
+ 60-fido-id.rules
60-input-id.rules
60-persistent-alsa.rules
60-persistent-input.rules
diff --git a/src/fuzz/fuzz-fido-id-desc.c b/src/fuzz/fuzz-fido-id-desc.c
new file mode 100644
index 0000000000..cf98dee044
--- /dev/null
+++ b/src/fuzz/fuzz-fido-id-desc.c
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <linux/hid.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "fido_id/fido_id_desc.h"
+#include "fuzz.h"
+#include "log.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ /* We don't want to fill the logs with messages about parse errors.
+ * Disable most logging if not running standalone */
+ if (!getenv("SYSTEMD_LOG_LEVEL"))
+ log_set_max_level(LOG_CRIT);
+
+ if (size > HID_MAX_DESCRIPTOR_SIZE)
+ return 0;
+ (void) is_fido_security_token_desc(data, size);
+
+ return 0;
+}
diff --git a/src/fuzz/fuzz-fido-id-desc.dict b/src/fuzz/fuzz-fido-id-desc.dict
new file mode 100644
index 0000000000..d2d2679e18
--- /dev/null
+++ b/src/fuzz/fuzz-fido-id-desc.dict
@@ -0,0 +1,6 @@
+"\xfe"
+"\x00"
+"\x01"
+"\xf1"
+"\xd0"
+"\xf1\xd0\x00\x01"
diff --git a/src/fuzz/meson.build b/src/fuzz/meson.build
index 1dbe28e57e..483a952421 100644
--- a/src/fuzz/meson.build
+++ b/src/fuzz/meson.build
@@ -47,4 +47,8 @@ fuzzers += [
[libsystemd_journal_remote,
libshared],
[]],
+ [['src/fuzz/fuzz-fido-id-desc.c',
+ 'src/udev/fido_id/fido_id_desc.c'],
+ [],
+ []]
]
diff --git a/src/test/meson.build b/src/test/meson.build
index 0998f59897..4259421f98 100644
--- a/src/test/meson.build
+++ b/src/test/meson.build
@@ -663,6 +663,10 @@ tests += [
[['src/test/test-bus-util.c'],
[],
[]],
+ [['src/test/test-fido-id-desc.c',
+ 'src/udev/fido_id/fido_id_desc.c'],
+ [],
+ []],
]
############################################################
diff --git a/src/test/test-fido-id-desc.c b/src/test/test-fido-id-desc.c
new file mode 100644
index 0000000000..cf55dd3266
--- /dev/null
+++ b/src/test/test-fido-id-desc.c
@@ -0,0 +1,85 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "fido_id/fido_id_desc.h"
+#include "macro.h"
+
+static void test_is_fido_security_token_desc__fido(void) {
+ static const uint8_t FIDO_HID_DESC_1[] = {
+ 0x06, 0xd0, 0xf1, 0x09, 0x01, 0xa1, 0x01, 0x09, 0x20, 0x15, 0x00, 0x26, 0xff, 0x00, 0x75,
+ 0x08, 0x95, 0x40, 0x81, 0x02, 0x09, 0x21, 0x15, 0x00, 0x26, 0xff, 0x00, 0x75, 0x08, 0x95,
+ 0x40, 0x91, 0x02, 0xc0,
+ };
+ assert_se(is_fido_security_token_desc(FIDO_HID_DESC_1, sizeof(FIDO_HID_DESC_1)) > 0);
+
+ static const uint8_t FIDO_HID_DESC_2[] = {
+ 0x05, 0x01, 0x09, 0x06, 0xa1, 0x01, 0x05, 0x07, 0x19, 0xe0, 0x29, 0xe7, 0x15, 0x00, 0x25,
+ 0x01, 0x75, 0x01, 0x95, 0x08, 0x81, 0x02, 0x95, 0x01, 0x75, 0x08, 0x81, 0x01, 0x95, 0x05,
+ 0x75, 0x01, 0x05, 0x08, 0x19, 0x01, 0x29, 0x05, 0x91, 0x02, 0x95, 0x01, 0x75, 0x03, 0x91,
+ 0x01, 0x95, 0x06, 0x75, 0x08, 0x15, 0x00, 0x25, 0x65, 0x05, 0x07, 0x19, 0x00, 0x29, 0x65,
+ 0x81, 0x00, 0x09, 0x03, 0x75, 0x08, 0x95, 0x08, 0xb1, 0x02, 0xc0,
+ 0x06, 0xd0, 0xf1, 0x09, 0x01, 0xa1, 0x01, 0x09, 0x20, 0x15, 0x00, 0x26, 0xff, 0x00, 0x75,
+ 0x08, 0x95, 0x40, 0x81, 0x02, 0x09, 0x21, 0x15, 0x00, 0x26, 0xff, 0x00, 0x75, 0x08, 0x95,
+ 0x40, 0x91, 0x02, 0xc0,
+ };
+ assert_se(is_fido_security_token_desc(FIDO_HID_DESC_2, sizeof(FIDO_HID_DESC_2)) > 0);
+}
+
+static void test_is_fido_security_token_desc__non_fido(void) {
+ /* Wrong usage page */
+ static const uint8_t NON_FIDO_HID_DESC_1[] = {
+ 0x06, 0xd0, 0xf0, 0x09, 0x01, 0xa1, 0x01, 0x09, 0x20, 0x15, 0x00, 0x26, 0xff, 0x00, 0x75,
+ 0x08, 0x95, 0x40, 0x81, 0x02, 0x09, 0x21, 0x15, 0x00, 0x26, 0xff, 0x00, 0x75, 0x08, 0x95,
+ 0x40, 0x91, 0x02, 0xc0,
+ };
+ assert_se(is_fido_security_token_desc(NON_FIDO_HID_DESC_1, sizeof(NON_FIDO_HID_DESC_1)) == 0);
+
+ /* Wrong usage */
+ static const uint8_t NON_FIDO_HID_DESC_2[] = {
+ 0x06, 0xd0, 0xf1, 0x09, 0x02, 0xa1, 0x01, 0x09, 0x20, 0x15, 0x00, 0x26, 0xff, 0x00, 0x75,
+ 0x08, 0x95, 0x40, 0x81, 0x02, 0x09, 0x21, 0x15, 0x00, 0x26, 0xff, 0x00, 0x75, 0x08, 0x95,
+ 0x40, 0x91, 0x02, 0xc0,
+ };
+ assert_se(is_fido_security_token_desc(NON_FIDO_HID_DESC_2, sizeof(NON_FIDO_HID_DESC_2)) == 0);
+
+ static const uint8_t NON_FIDO_HID_DESC_3[] = {
+ 0x05, 0x01, 0x09, 0x06, 0xa1, 0x01, 0x05, 0x07, 0x19, 0xe0, 0x29, 0xe7, 0x15, 0x00, 0x25,
+ 0x01, 0x75, 0x01, 0x95, 0x08, 0x81, 0x02, 0x95, 0x01, 0x75, 0x08, 0x81, 0x01, 0x95, 0x05,
+ 0x75, 0x01, 0x05, 0x08, 0x19, 0x01, 0x29, 0x05, 0x91, 0x02, 0x95, 0x01, 0x75, 0x03, 0x91,
+ 0x01, 0x95, 0x06, 0x75, 0x08, 0x15, 0x00, 0x25, 0x65, 0x05, 0x07, 0x19, 0x00, 0x29, 0x65,
+ 0x81, 0x00, 0x09, 0x03, 0x75, 0x08, 0x95, 0x08, 0xb1, 0x02, 0xc0,
+ };
+ assert_se(is_fido_security_token_desc(NON_FIDO_HID_DESC_3, sizeof(NON_FIDO_HID_DESC_3)) == 0);
+}
+
+static void test_is_fido_security_token_desc__invalid(void) {
+ /* Size coded on 1 byte, but no byte given */
+ static const uint8_t INVALID_HID_DESC_1[] = { 0x01 };
+ assert_se(is_fido_security_token_desc(INVALID_HID_DESC_1, sizeof(INVALID_HID_DESC_1)) < 0);
+
+ /* Size coded on 2 bytes, but only 1 byte given */
+ static const uint8_t INVALID_HID_DESC_2[] = { 0x02, 0x01 };
+ assert_se(is_fido_security_token_desc(INVALID_HID_DESC_2, sizeof(INVALID_HID_DESC_2)) < 0);
+
+ /* Size coded on 4 bytes, but only 3 bytes given */
+ static const uint8_t INVALID_HID_DESC_3[] = { 0x03, 0x01, 0x02, 0x03 };
+ assert_se(is_fido_security_token_desc(INVALID_HID_DESC_3, sizeof(INVALID_HID_DESC_3)) < 0);
+
+ /* Long item without a size byte */
+ static const uint8_t INVALID_HID_DESC_4[] = { 0xfe };
+ assert_se(is_fido_security_token_desc(INVALID_HID_DESC_4, sizeof(INVALID_HID_DESC_4)) < 0);
+
+ /* Usage pages are coded on at most 2 bytes */
+ static const uint8_t INVALID_HID_DESC_5[] = { 0x07, 0x01, 0x02, 0x03, 0x04 };
+ assert_se(is_fido_security_token_desc(INVALID_HID_DESC_5, sizeof(INVALID_HID_DESC_5)) < 0);
+}
+
+int main(int argc, char *argv[]) {
+ test_is_fido_security_token_desc__fido();
+ test_is_fido_security_token_desc__non_fido();
+ test_is_fido_security_token_desc__invalid();
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/udev/fido_id/fido_id.c b/src/udev/fido_id/fido_id.c
new file mode 100644
index 0000000000..7e1cc804f2
--- /dev/null
+++ b/src/udev/fido_id/fido_id.c
@@ -0,0 +1,103 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+/*
+ * Identifies FIDO CTAP1 ("U2F")/CTAP2 security tokens based on the usage declared in their report
+ * descriptor and outputs suitable environment variables.
+ *
+ * Inspired by Andrew Lutomirski's 'u2f-hidraw-policy.c'
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/hid.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "sd-device.h"
+
+#include "device-internal.h"
+#include "device-private.h"
+#include "device-util.h"
+#include "fd-util.h"
+#include "fido_id_desc.h"
+#include "log.h"
+#include "macro.h"
+#include "path-util.h"
+#include "string-util.h"
+#include "udev-util.h"
+
+static int run(int argc, char **argv) {
+ _cleanup_(sd_device_unrefp) struct sd_device *device = NULL;
+ _cleanup_free_ char *desc_path = NULL;
+ _cleanup_close_ int fd = -1;
+
+ struct sd_device *hid_device;
+ const char *sys_path;
+ uint8_t desc[HID_MAX_DESCRIPTOR_SIZE];
+ ssize_t desc_len;
+
+ int r;
+
+ log_set_target(LOG_TARGET_AUTO);
+ udev_parse_config();
+ log_parse_environment();
+ log_open();
+
+ if (argc > 2)
+ return log_error_errno(EINVAL, "Usage: %s [SYSFS_PATH]", program_invocation_short_name);
+
+ if (argc == 1) {
+ r = device_new_from_strv(&device, environ);
+ if (r < 0)
+ return log_error_errno(r, "Failed to get current device from environment: %m");
+ } else {
+ r = sd_device_new_from_syspath(&device, argv[1]);
+ if (r < 0)
+ return log_error_errno(r, "Failed to get device from syspath: %m");
+ }
+
+ r = sd_device_get_parent(device, &hid_device);
+ if (r < 0)
+ return log_device_error_errno(device, r, "Failed to get parent HID device: %m");
+
+ r = sd_device_get_syspath(hid_device, &sys_path);
+ if (r < 0)
+ return log_device_error_errno(hid_device, r, "Failed to get syspath for HID device: %m");
+
+ desc_path = path_join(NULL, sys_path, "report_descriptor");
+ if (!desc_path)
+ return log_oom();
+
+ fd = open(desc_path, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
+ if (fd < 0)
+ return log_device_error_errno(hid_device, errno,
+ "Failed to open report descriptor at '%s': %m", desc_path);
+
+ desc_len = read(fd, desc, sizeof(desc));
+ if (desc_len < 0)
+ return log_device_error_errno(hid_device, errno,
+ "Failed to read report descriptor at '%s': %m", desc_path);
+ if (desc_len == 0)
+ return log_device_debug_errno(hid_device, EINVAL,
+ "Empty report descriptor at '%s'.", desc_path);
+
+ r = is_fido_security_token_desc(desc, desc_len);
+ if (r < 0)
+ return log_device_debug_errno(hid_device, r,
+ "Failed to parse report descriptor at '%s'.", desc_path);
+ if (r > 0) {
+ printf("ID_FIDO_TOKEN=1\n");
+ printf("ID_SECURITY_TOKEN=1\n");
+ }
+
+ return 0;
+}
+
+int main(int argc, char *argv[]) {
+ int r;
+
+ r = run(argc, argv);
+
+ return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+}
diff --git a/src/udev/fido_id/fido_id_desc.c b/src/udev/fido_id/fido_id_desc.c
new file mode 100644
index 0000000000..bbfcf93709
--- /dev/null
+++ b/src/udev/fido_id/fido_id_desc.c
@@ -0,0 +1,92 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+/* Inspired by Andrew Lutomirski's 'u2f-hidraw-policy.c' */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "fido_id_desc.h"
+
+#define HID_RPTDESC_FIRST_BYTE_LONG_ITEM 0xfeu
+#define HID_RPTDESC_TYPE_GLOBAL 0x1u
+#define HID_RPTDESC_TYPE_LOCAL 0x2u
+#define HID_RPTDESC_TAG_USAGE_PAGE 0x0u
+#define HID_RPTDESC_TAG_USAGE 0x0u
+
+/*
+ * HID usage for FIDO CTAP1 ("U2F") and CTAP2 security tokens.
+ * https://fidoalliance.org/specs/fido-u2f-v1.0-ps-20141009/fido-u2f-u2f_hid.h-v1.0-ps-20141009.txt
+ * https://fidoalliance.org/specs/fido-v2.0-ps-20190130/fido-client-to-authenticator-protocol-v2.0-ps-20190130.html#usb-discovery
+ * https://www.usb.org/sites/default/files/hutrr48.pdf
+ */
+#define FIDO_FULL_USAGE_CTAPHID 0xf1d00001u
+
+/*
+ * Parses a HID report descriptor and identifies FIDO CTAP1 ("U2F")/CTAP2 security tokens based on their
+ * declared usage.
+ * A positive return value indicates that the report descriptor belongs to a FIDO security token.
+ * https://www.usb.org/sites/default/files/documents/hid1_11.pdf (Section 6.2.2)
+ */
+int is_fido_security_token_desc(const uint8_t *desc, size_t desc_len) {
+ uint32_t usage = 0;
+
+ for (size_t pos = 0; pos < desc_len; ) {
+ uint8_t tag, type, size_code;
+ size_t size;
+ uint32_t value;
+
+ /* Report descriptors consists of short items (1-5 bytes) and long items (3-258 bytes). */
+ if (desc[pos] == HID_RPTDESC_FIRST_BYTE_LONG_ITEM) {
+ /* No long items are defined in the spec; skip them.
+ * The length of the data in a long item is contained in the byte after the long
+ * item tag. The header consists of three bytes: special long item tag, length,
+ * actual tag. */
+ if (pos + 1 >= desc_len)
+ return -EINVAL;
+ pos += desc[pos + 1] + 3;
+ continue;
+ }
+
+ /* The first byte of a short item encodes tag, type and size. */
+ tag = desc[pos] >> 4; /* Bits 7 to 4 */
+ type = (desc[pos] >> 2) & 0x3; /* Bits 3 and 2 */
+ size_code = desc[pos] & 0x3; /* Bits 1 and 0 */
+ /* Size is coded as follows:
+ * 0 -> 0 bytes, 1 -> 1 byte, 2 -> 2 bytes, 3 -> 4 bytes
+ */
+ size = size_code < 3 ? size_code : 4;
+ /* Consume header byte. */
+ pos++;
+
+ /* Extract the item value coded on size bytes. */
+ if (pos + size > desc_len)
+ return -EINVAL;
+ value = 0;
+ for (size_t i = 0; i < size; i++)
+ value |= (uint32_t) desc[pos + i] << (8 * i);
+ /* Consume value bytes. */
+ pos += size;
+
+ if (type == HID_RPTDESC_TYPE_GLOBAL && tag == HID_RPTDESC_TAG_USAGE_PAGE) {
+ /* A usage page is a 16 bit value coded on at most 16 bits. */
+ if (size > 2)
+ return -EINVAL;
+ /* A usage page sets the upper 16 bits of a following usage. */
+ usage = (value & 0x0000ffffu) << 16;
+ }
+
+ if (type == HID_RPTDESC_TYPE_LOCAL && tag == HID_RPTDESC_TAG_USAGE) {
+ /* A usage is a 32 bit value, but is prepended with the current usage page if
+ * coded on less than 4 bytes (that is, at most 2 bytes). */
+ if (size == 4)
+ usage = value;
+ else
+ usage = (usage & 0xffff0000u) | (value & 0x0000ffffu);
+ if (usage == FIDO_FULL_USAGE_CTAPHID)
+ return 1;
+ }
+ }
+
+ return 0;
+}
diff --git a/src/udev/fido_id/fido_id_desc.h b/src/udev/fido_id/fido_id_desc.h
new file mode 100644
index 0000000000..c813a3a454
--- /dev/null
+++ b/src/udev/fido_id/fido_id_desc.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#pragma once
+
+#include <stddef.h>
+#include <stdint.h>
+
+int is_fido_security_token_desc(const uint8_t *desc, size_t desc_len);
diff --git a/src/udev/meson.build b/src/udev/meson.build
index 3bcd2bd3d7..5931a6da7d 100644
--- a/src/udev/meson.build
+++ b/src/udev/meson.build
@@ -160,6 +160,9 @@ libudev_core = static_library(
foreach prog : [['ata_id/ata_id.c'],
['cdrom_id/cdrom_id.c'],
['collect/collect.c'],
+ ['fido_id/fido_id.c',
+ 'fido_id/fido_id_desc.c',
+ 'fido_id/fido_id_desc.h'],
['scsi_id/scsi_id.c',
'scsi_id/scsi_id.h',
'scsi_id/scsi_serial.c',
diff --git a/test/fuzz/fuzz-fido-id-desc/crash0 b/test/fuzz/fuzz-fido-id-desc/crash0
new file mode 100644
index 0000000000..e066656502
--- /dev/null
+++ b/test/fuzz/fuzz-fido-id-desc/crash0
@@ -0,0 +1 @@
+Ì
\ No newline at end of file
diff --git a/test/fuzz/fuzz-fido-id-desc/crash1 b/test/fuzz/fuzz-fido-id-desc/crash1
new file mode 100644
index 0000000000..aef3e18335
--- /dev/null
+++ b/test/fuzz/fuzz-fido-id-desc/crash1
@@ -0,0 +1 @@
+øûøûûÜ
\ No newline at end of file
diff --git a/test/fuzz/fuzz-fido-id-desc/report0 b/test/fuzz/fuzz-fido-id-desc/report0
new file mode 100644
index 0000000000000000000000000000000000000000..48757cba682ffddd5a1ddd8988bb8bcdc7db0a7a
GIT binary patch
literal 71
zcmZQ&<YZgO$jUDHK=ZjMgDPVw<5Z4Drm2jj9F2@qSxXsNIV2f1Sto)-m?tt$Wh><X
Xs!9c_XV6S-WZ+~j<(SH`k?8;c6l@Pq
literal 0
HcmV?d00001
diff --git a/test/fuzz/fuzz-fido-id-desc/report1 b/test/fuzz/fuzz-fido-id-desc/report1
new file mode 100644
index 0000000000000000000000000000000000000000..b70b7fb871aeccf4074ccbd20e3cdbaca42e23b3
GIT binary patch
literal 34
icmZR(@R5^oAtR@PD1+L6hEk5H4vkElig3<ErUL+_0SUDL
literal 0
HcmV?d00001

View File

@ -0,0 +1,33 @@
From c3be943b30689f77ded9f431fdafb666769aea89 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Tue, 27 Aug 2019 19:00:34 +0200
Subject: [PATCH] shared/but-util: drop trusted annotation from
bus_open_system_watch_bind_with_description()
https://bugzilla.redhat.com/show_bug.cgi?id=1746057
This only affects systemd-resolved. bus_open_system_watch_bind_with_description()
is also used in timesyncd, but it has no methods, only read-only properties, and
in networkd, but it annotates all methods with SD_BUS_VTABLE_UNPRIVILEGED and does
polkit checks.
Resolves: #1746857
---
src/shared/bus-util.c | 4 ----
1 file changed, 4 deletions(-)
diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c
index a4f2deba31..302dbb4c2e 100644
--- a/src/shared/bus-util.c
+++ b/src/shared/bus-util.c
@@ -1699,10 +1699,6 @@ int bus_open_system_watch_bind_with_description(sd_bus **ret, const char *descri
if (r < 0)
return r;
- r = sd_bus_set_trusted(bus, true);
- if (r < 0)
- return r;
-
r = sd_bus_negotiate_creds(bus, true, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_EFFECTIVE_CAPS);
if (r < 0)
return r;

View File

@ -0,0 +1,50 @@
From 7e0f9a0cd4053fcc713a99ada3d0d50793b83564 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Tue, 27 Aug 2019 19:00:50 +0200
Subject: [PATCH] sd-bus: adjust indentation of comments
Related: #1746857
---
src/libsystemd/sd-bus/sd-bus.c | 3 +--
src/shared/bus-util.c | 7 ++++---
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c
index 3583e24e64..1c9e967ae0 100644
--- a/src/libsystemd/sd-bus/sd-bus.c
+++ b/src/libsystemd/sd-bus/sd-bus.c
@@ -1341,8 +1341,7 @@ _public_ int sd_bus_open_user_with_description(sd_bus **ret, const char *descrip
b->bus_client = true;
b->is_user = true;
- /* We don't do any per-method access control on the user
- * bus. */
+ /* We don't do any per-method access control on the user bus. */
b->trusted = true;
b->is_local = true;
diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c
index 302dbb4c2e..2d908eb45c 100644
--- a/src/shared/bus-util.c
+++ b/src/shared/bus-util.c
@@ -1675,7 +1675,8 @@ int bus_open_system_watch_bind_with_description(sd_bus **ret, const char *descri
assert(ret);
- /* Match like sd_bus_open_system(), but with the "watch_bind" feature and the Connected() signal turned on. */
+ /* Match like sd_bus_open_system(), but with the "watch_bind" feature and the Connected() signal
+ * turned on. */
r = sd_bus_new(&bus);
if (r < 0)
@@ -1890,8 +1891,8 @@ int bus_reply_pair_array(sd_bus_message *m, char **l) {
assert(m);
- /* Reply to the specified message with a message containing a dictionary put together from the specified
- * strv */
+ /* Reply to the specified message with a message containing a dictionary put together from the
+ * specified strv */
r = sd_bus_message_new_method_return(m, &reply);
if (r < 0)

View File

@ -0,0 +1,46 @@
From d95afbca80cf52f0bc84b2e1b4af6aadda007138 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Tue, 27 Aug 2019 19:02:53 +0200
Subject: [PATCH] resolved: do not run loop twice
This doesn't matter much, but let's just do the loop once and allocate
the populate the result set on the fly. If we find an error, it'll get
cleaned up automatically.
Related: #1746857
---
src/resolve/resolved-link-bus.c | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)
diff --git a/src/resolve/resolved-link-bus.c b/src/resolve/resolved-link-bus.c
index b1581740d8..46d2b11636 100644
--- a/src/resolve/resolved-link-bus.c
+++ b/src/resolve/resolved-link-bus.c
@@ -492,6 +492,10 @@ int bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message *message, v
if (r < 0)
return r;
+ ns = set_new(&dns_name_hash_ops);
+ if (!ns)
+ return -ENOMEM;
+
r = sd_bus_message_read_strv(message, &ntas);
if (r < 0)
return r;
@@ -501,14 +505,9 @@ int bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message *message, v
if (r < 0)
return r;
if (r == 0)
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid negative trust anchor domain: %s", *i);
- }
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+ "Invalid negative trust anchor domain: %s", *i);
- ns = set_new(&dns_name_hash_ops);
- if (!ns)
- return -ENOMEM;
-
- STRV_FOREACH(i, ntas) {
r = set_put_strdup(ns, *i);
if (r < 0)
return r;

View File

@ -0,0 +1,347 @@
From ddd08e75b1e7fa1f6dfef3d30a0c1ef8c63e4d07 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Tue, 27 Aug 2019 19:25:05 +0200
Subject: [PATCH] resolved: allow access to Set*Link and Revert methods through
polkit
This matches what is done in networkd very closely. In fact even the
policy descriptions are all identical (with s/network/resolve), except
for the last one:
resolved has org.freedesktop.resolve1.revert while
networkd has org.freedesktop.network1.revert-ntp and
org.freedesktop.network1.revert-dns so the description is a bit different.
Conflicts:
src/resolve/resolved-bus.c
src/resolve/resolved-link-bus.c
Related: #1746857
---
src/resolve/org.freedesktop.resolve1.policy | 99 +++++++++++++++++++++
src/resolve/resolved-bus.c | 22 ++---
src/resolve/resolved-link-bus.c | 97 +++++++++++++++++---
3 files changed, 197 insertions(+), 21 deletions(-)
diff --git a/src/resolve/org.freedesktop.resolve1.policy b/src/resolve/org.freedesktop.resolve1.policy
index b65ba3e56a..592c4eb8b0 100644
--- a/src/resolve/org.freedesktop.resolve1.policy
+++ b/src/resolve/org.freedesktop.resolve1.policy
@@ -40,4 +40,103 @@
<annotate key="org.freedesktop.policykit.owner">unix-user:systemd-resolve</annotate>
</action>
+ <action id="org.freedesktop.resolve1.set-dns-servers">
+ <description gettext-domain="systemd">Set DNS servers</description>
+ <message gettext-domain="systemd">Authentication is required to set DNS servers.</message>
+ <defaults>
+ <allow_any>auth_admin</allow_any>
+ <allow_inactive>auth_admin</allow_inactive>
+ <allow_active>auth_admin_keep</allow_active>
+ </defaults>
+ <annotate key="org.freedesktop.policykit.owner">unix-user:systemd-resolve</annotate>
+ </action>
+
+ <action id="org.freedesktop.resolve1.set-domains">
+ <description gettext-domain="systemd">Set domains</description>
+ <message gettext-domain="systemd">Authentication is required to set domains.</message>
+ <defaults>
+ <allow_any>auth_admin</allow_any>
+ <allow_inactive>auth_admin</allow_inactive>
+ <allow_active>auth_admin_keep</allow_active>
+ </defaults>
+ <annotate key="org.freedesktop.policykit.owner">unix-user:systemd-resolve</annotate>
+ </action>
+
+ <action id="org.freedesktop.resolve1.set-default-route">
+ <description gettext-domain="systemd">Set default route</description>
+ <message gettext-domain="systemd">Authentication is required to set default route.</message>
+ <defaults>
+ <allow_any>auth_admin</allow_any>
+ <allow_inactive>auth_admin</allow_inactive>
+ <allow_active>auth_admin_keep</allow_active>
+ </defaults>
+ <annotate key="org.freedesktop.policykit.owner">unix-user:systemd-resolve</annotate>
+ </action>
+
+ <action id="org.freedesktop.resolve1.set-llmnr">
+ <description gettext-domain="systemd">Enable/disable LLMNR</description>
+ <message gettext-domain="systemd">Authentication is required to enable or disable LLMNR.</message>
+ <defaults>
+ <allow_any>auth_admin</allow_any>
+ <allow_inactive>auth_admin</allow_inactive>
+ <allow_active>auth_admin_keep</allow_active>
+ </defaults>
+ <annotate key="org.freedesktop.policykit.owner">unix-user:systemd-resolve</annotate>
+ </action>
+
+ <action id="org.freedesktop.resolve1.set-mdns">
+ <description gettext-domain="systemd">Enable/disable multicast DNS</description>
+ <message gettext-domain="systemd">Authentication is required to enable or disable multicast DNS.</message>
+ <defaults>
+ <allow_any>auth_admin</allow_any>
+ <allow_inactive>auth_admin</allow_inactive>
+ <allow_active>auth_admin_keep</allow_active>
+ </defaults>
+ <annotate key="org.freedesktop.policykit.owner">unix-user:systemd-resolve</annotate>
+ </action>
+
+ <action id="org.freedesktop.resolve1.set-dns-over-tls">
+ <description gettext-domain="systemd">Enable/disable DNS over TLS</description>
+ <message gettext-domain="systemd">Authentication is required to enable or disable DNS over TLS.</message>
+ <defaults>
+ <allow_any>auth_admin</allow_any>
+ <allow_inactive>auth_admin</allow_inactive>
+ <allow_active>auth_admin_keep</allow_active>
+ </defaults>
+ <annotate key="org.freedesktop.policykit.owner">unix-user:systemd-resolve</annotate>
+ </action>
+
+ <action id="org.freedesktop.resolve1.set-dnssec">
+ <description gettext-domain="systemd">Enable/disable DNSSEC</description>
+ <message gettext-domain="systemd">Authentication is required to enable or disable DNSSEC.</message>
+ <defaults>
+ <allow_any>auth_admin</allow_any>
+ <allow_inactive>auth_admin</allow_inactive>
+ <allow_active>auth_admin_keep</allow_active>
+ </defaults>
+ <annotate key="org.freedesktop.policykit.owner">unix-user:systemd-resolve</annotate>
+ </action>
+
+ <action id="org.freedesktop.resolve1.set-dnssec-negative-trust-anchors">
+ <description gettext-domain="systemd">Set DNSSEC Negative Trust Anchors</description>
+ <message gettext-domain="systemd">Authentication is required to set DNSSEC Negative Trust Anchros.</message>
+ <defaults>
+ <allow_any>auth_admin</allow_any>
+ <allow_inactive>auth_admin</allow_inactive>
+ <allow_active>auth_admin_keep</allow_active>
+ </defaults>
+ <annotate key="org.freedesktop.policykit.owner">unix-user:systemd-resolve</annotate>
+ </action>
+
+ <action id="org.freedesktop.resolve1.revert">
+ <description gettext-domain="systemd">Revert name resolution settings</description>
+ <message gettext-domain="systemd">Authentication is required to revert name resolution settings.</message>
+ <defaults>
+ <allow_any>auth_admin</allow_any>
+ <allow_inactive>auth_admin</allow_inactive>
+ <allow_active>auth_admin_keep</allow_active>
+ </defaults>
+ <annotate key="org.freedesktop.policykit.owner">unix-user:systemd-resolve</annotate>
+ </action>
+
</policyconfig>
diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c
index da0a909dd6..4d6cc4fd48 100644
--- a/src/resolve/resolved-bus.c
+++ b/src/resolve/resolved-bus.c
@@ -1848,18 +1848,18 @@ static const sd_bus_vtable resolve_vtable[] = {
SD_BUS_METHOD("ResolveAddress", "iiayt", "a(is)t", bus_method_resolve_address, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("ResolveRecord", "isqqt", "a(iqqay)t", bus_method_resolve_record, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("ResolveService", "isssit", "a(qqqsa(iiay)s)aayssst", bus_method_resolve_service, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("ResetStatistics", NULL, NULL, bus_method_reset_statistics, 0),
- SD_BUS_METHOD("FlushCaches", NULL, NULL, bus_method_flush_caches, 0),
- SD_BUS_METHOD("ResetServerFeatures", NULL, NULL, bus_method_reset_server_features, 0),
+ SD_BUS_METHOD("ResetStatistics", NULL, NULL, bus_method_reset_statistics, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("FlushCaches", NULL, NULL, bus_method_flush_caches, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("ResetServerFeatures", NULL, NULL, bus_method_reset_server_features, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("GetLink", "i", "o", bus_method_get_link, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("SetLinkDNS", "ia(iay)", NULL, bus_method_set_link_dns_servers, 0),
- SD_BUS_METHOD("SetLinkDomains", "ia(sb)", NULL, bus_method_set_link_domains, 0),
- SD_BUS_METHOD("SetLinkLLMNR", "is", NULL, bus_method_set_link_llmnr, 0),
- SD_BUS_METHOD("SetLinkMulticastDNS", "is", NULL, bus_method_set_link_mdns, 0),
- SD_BUS_METHOD("SetLinkDNSOverTLS", "is", NULL, bus_method_set_link_dns_over_tls, 0),
- SD_BUS_METHOD("SetLinkDNSSEC", "is", NULL, bus_method_set_link_dnssec, 0),
- SD_BUS_METHOD("SetLinkDNSSECNegativeTrustAnchors", "ias", NULL, bus_method_set_link_dnssec_negative_trust_anchors, 0),
- SD_BUS_METHOD("RevertLink", "i", NULL, bus_method_revert_link, 0),
+ SD_BUS_METHOD("SetLinkDNS", "ia(iay)", NULL, bus_method_set_link_dns_servers, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("SetLinkDomains", "ia(sb)", NULL, bus_method_set_link_domains, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("SetLinkLLMNR", "is", NULL, bus_method_set_link_llmnr, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("SetLinkMulticastDNS", "is", NULL, bus_method_set_link_mdns, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("SetLinkDNSOverTLS", "is", NULL, bus_method_set_link_dns_over_tls, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("SetLinkDNSSEC", "is", NULL, bus_method_set_link_dnssec, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("SetLinkDNSSECNegativeTrustAnchors", "ias", NULL, bus_method_set_link_dnssec_negative_trust_anchors, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("RevertLink", "i", NULL, bus_method_revert_link, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("RegisterService", "sssqqqaa{say}", "o", bus_method_register_service, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("UnregisterService", "o", NULL, bus_method_unregister_service, SD_BUS_VTABLE_UNPRIVILEGED),
diff --git a/src/resolve/resolved-link-bus.c b/src/resolve/resolved-link-bus.c
index 46d2b11636..bf3e42264e 100644
--- a/src/resolve/resolved-link-bus.c
+++ b/src/resolve/resolved-link-bus.c
@@ -1,5 +1,9 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
+#include <net/if.h>
+#include <netinet/in.h>
+#include <sys/capability.h>
+
#include "alloc-util.h"
#include "bus-common-errors.h"
#include "bus-util.h"
@@ -9,6 +13,7 @@
#include "resolved-link-bus.h"
#include "resolved-resolv-conf.h"
#include "strv.h"
+#include "user-util.h"
static BUS_DEFINE_PROPERTY_GET(property_get_dnssec_supported, "b", Link, link_dnssec_supported);
static BUS_DEFINE_PROPERTY_GET2(property_get_dnssec_mode, "s", Link, link_get_dnssec_mode, dnssec_mode_to_string);
@@ -235,6 +240,15 @@ int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_
if (r < 0)
return r;
+ r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
+ "org.freedesktop.resolve1.set-dns-servers",
+ NULL, true, UID_INVALID,
+ &l->manager->polkit_registry, error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* Polkit will call us back */
+
dns_server_mark_all(l->dns_servers);
for (i = 0; i < n; i++) {
@@ -298,12 +312,21 @@ int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root domain is not suitable as search domain");
}
- dns_search_domain_mark_all(l->search_domains);
-
r = sd_bus_message_rewind(message, false);
if (r < 0)
return r;
+ r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
+ "org.freedesktop.resolve1.set-domains",
+ NULL, true, UID_INVALID,
+ &l->manager->polkit_registry, error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* Polkit will call us back */
+
+ dns_search_domain_mark_all(l->search_domains);
+
for (;;) {
DnsSearchDomain *d;
const char *name;
@@ -371,6 +394,15 @@ int bus_link_method_set_llmnr(sd_bus_message *message, void *userdata, sd_bus_er
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid LLMNR setting: %s", llmnr);
}
+ r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
+ "org.freedesktop.resolve1.set-llmnr",
+ NULL, true, UID_INVALID,
+ &l->manager->polkit_registry, error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* Polkit will call us back */
+
l->llmnr_support = mode;
link_allocate_scopes(l);
link_add_rrs(l, false);
@@ -405,6 +437,15 @@ int bus_link_method_set_mdns(sd_bus_message *message, void *userdata, sd_bus_err
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid MulticastDNS setting: %s", mdns);
}
+ r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
+ "org.freedesktop.resolve1.set-mdns",
+ NULL, true, UID_INVALID,
+ &l->manager->polkit_registry, error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* Polkit will call us back */
+
l->mdns_support = mode;
link_allocate_scopes(l);
link_add_rrs(l, false);
@@ -439,6 +480,15 @@ int bus_link_method_set_dns_over_tls(sd_bus_message *message, void *userdata, sd
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid DNSOverTLS setting: %s", dns_over_tls);
}
+ r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
+ "org.freedesktop.resolve1.set-dns-over-tls",
+ NULL, true, UID_INVALID,
+ &l->manager->polkit_registry, error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* Polkit will call us back */
+
link_set_dns_over_tls_mode(l, mode);
(void) link_save_user(l);
@@ -471,6 +521,15 @@ int bus_link_method_set_dnssec(sd_bus_message *message, void *userdata, sd_bus_e
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid DNSSEC setting: %s", dnssec);
}
+ r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
+ "org.freedesktop.resolve1.set-dnssec",
+ NULL, true, UID_INVALID,
+ &l->manager->polkit_registry, error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* Polkit will call us back */
+
link_set_dnssec_mode(l, mode);
(void) link_save_user(l);
@@ -513,6 +572,15 @@ int bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message *message, v
return r;
}
+ r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
+ "org.freedesktop.resolve1.set-dnssec-negative-trust-anchors",
+ NULL, true, UID_INVALID,
+ &l->manager->polkit_registry, error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* Polkit will call us back */
+
set_free_free(l->dnssec_negative_trust_anchors);
l->dnssec_negative_trust_anchors = TAKE_PTR(ns);
@@ -532,6 +600,15 @@ int bus_link_method_revert(sd_bus_message *message, void *userdata, sd_bus_error
if (r < 0)
return r;
+ r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
+ "org.freedesktop.resolve1.revert",
+ NULL, true, UID_INVALID,
+ &l->manager->polkit_registry, error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* Polkit will call us back */
+
link_flush_settings(l);
link_allocate_scopes(l);
link_add_rrs(l, false);
@@ -556,14 +633,14 @@ const sd_bus_vtable link_vtable[] = {
SD_BUS_PROPERTY("DNSSECNegativeTrustAnchors", "as", property_get_ntas, 0, 0),
SD_BUS_PROPERTY("DNSSECSupported", "b", property_get_dnssec_supported, 0, 0),
- SD_BUS_METHOD("SetDNS", "a(iay)", NULL, bus_link_method_set_dns_servers, 0),
- SD_BUS_METHOD("SetDomains", "a(sb)", NULL, bus_link_method_set_domains, 0),
- SD_BUS_METHOD("SetLLMNR", "s", NULL, bus_link_method_set_llmnr, 0),
- SD_BUS_METHOD("SetMulticastDNS", "s", NULL, bus_link_method_set_mdns, 0),
- SD_BUS_METHOD("SetDNSOverTLS", "s", NULL, bus_link_method_set_dns_over_tls, 0),
- SD_BUS_METHOD("SetDNSSEC", "s", NULL, bus_link_method_set_dnssec, 0),
- SD_BUS_METHOD("SetDNSSECNegativeTrustAnchors", "as", NULL, bus_link_method_set_dnssec_negative_trust_anchors, 0),
- SD_BUS_METHOD("Revert", NULL, NULL, bus_link_method_revert, 0),
+ SD_BUS_METHOD("SetDNS", "a(iay)", NULL, bus_link_method_set_dns_servers, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("SetDomains", "a(sb)", NULL, bus_link_method_set_domains, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("SetLLMNR", "s", NULL, bus_link_method_set_llmnr, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("SetMulticastDNS", "s", NULL, bus_link_method_set_mdns, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("SetDNSOverTLS", "s", NULL, bus_link_method_set_dns_over_tls, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("SetDNSSEC", "s", NULL, bus_link_method_set_dnssec, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("SetDNSSECNegativeTrustAnchors", "as", NULL, bus_link_method_set_dnssec_negative_trust_anchors, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("Revert", NULL, NULL, bus_link_method_revert, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_VTABLE_END
};

View File

@ -0,0 +1,48 @@
From 7b00cae817e54ee3398ad3b42ec69a3b63676562 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Tue, 27 Aug 2019 19:28:19 +0200
Subject: [PATCH] resolved: query polkit only after parsing the data
That's what we do everywhere else because it leads to nicer user experience.
Related: #1746857
---
src/resolve/resolved-bus.c | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c
index 4d6cc4fd48..3f6a6f9e12 100644
--- a/src/resolve/resolved-bus.c
+++ b/src/resolve/resolved-bus.c
@@ -1632,15 +1632,6 @@ static int bus_method_register_service(sd_bus_message *message, void *userdata,
if (m->mdns_support != RESOLVE_SUPPORT_YES)
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Support for MulticastDNS is disabled");
- r = bus_verify_polkit_async(message, CAP_SYS_ADMIN,
- "org.freedesktop.resolve1.register-service",
- NULL, false, UID_INVALID,
- &m->polkit_registry, error);
- if (r < 0)
- return r;
- if (r == 0)
- return 1; /* Polkit will call us back */
-
service = new0(DnssdService, 1);
if (!service)
return log_oom();
@@ -1765,6 +1756,15 @@ static int bus_method_register_service(sd_bus_message *message, void *userdata,
if (r < 0)
return r;
+ r = bus_verify_polkit_async(message, CAP_SYS_ADMIN,
+ "org.freedesktop.resolve1.register-service",
+ NULL, false, UID_INVALID,
+ &m->polkit_registry, error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* Polkit will call us back */
+
r = hashmap_ensure_allocated(&m->dnssd_services, &string_hash_ops);
if (r < 0)
return r;

View File

@ -0,0 +1,48 @@
From 4d2145e3edd6ba6ac2e52a232fa5059ecdacaead Mon Sep 17 00:00:00 2001
From: Evgeny Vereshchagin <evvers@ya.ru>
Date: Mon, 24 Dec 2018 00:29:56 +0100
Subject: [PATCH] journal: rely on _cleanup_free_ to free a temporary string
used in client_context_read_cgroup
Closes https://github.com/systemd/systemd/issues/11253.
(cherry picked from commit ef30f7cac18a810814ada7e6a68a31d48cc9fccd)
Resolves: #1764560
---
src/journal/journald-context.c | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/src/journal/journald-context.c b/src/journal/journald-context.c
index c8e97e16de..3a768094d9 100644
--- a/src/journal/journald-context.c
+++ b/src/journal/journald-context.c
@@ -282,7 +282,7 @@ static int client_context_read_label(
}
static int client_context_read_cgroup(Server *s, ClientContext *c, const char *unit_id) {
- char *t = NULL;
+ _cleanup_free_ char *t = NULL;
int r;
assert(c);
@@ -290,7 +290,6 @@ static int client_context_read_cgroup(Server *s, ClientContext *c, const char *u
/* Try to acquire the current cgroup path */
r = cg_pid_get_path_shifted(c->pid, s->cgroup_root, &t);
if (r < 0 || empty_or_root(t)) {
-
/* We use the unit ID passed in as fallback if we have nothing cached yet and cg_pid_get_path_shifted()
* failed or process is running in a root cgroup. Zombie processes are automatically migrated to root cgroup
* on cgroupsv1 and we want to be able to map log messages from them too. */
@@ -304,10 +303,8 @@ static int client_context_read_cgroup(Server *s, ClientContext *c, const char *u
}
/* Let's shortcut this if the cgroup path didn't change */
- if (streq_ptr(c->cgroup, t)) {
- free(t);
+ if (streq_ptr(c->cgroup, t))
return 0;
- }
free_and_replace(c->cgroup, t);

View File

@ -0,0 +1,90 @@
From 76176de0889c3e8b9b3a176da24e4f8dbbd380a3 Mon Sep 17 00:00:00 2001
From: Jan Synacek <jsynacek@redhat.com>
Date: Wed, 2 Oct 2019 11:59:41 +0200
Subject: [PATCH] basic/user-util: allow dots in user names
(based on commit 1a29610f5fa1bcb2eeb37d2c6b79d8d1a6dbb865)
Resolves: #1717603
---
src/basic/user-util.c | 9 ++++++---
src/test/test-user-util.c | 8 ++++----
2 files changed, 10 insertions(+), 7 deletions(-)
diff --git a/src/basic/user-util.c b/src/basic/user-util.c
index c533f67025..d92969c966 100644
--- a/src/basic/user-util.c
+++ b/src/basic/user-util.c
@@ -575,11 +575,14 @@ bool valid_user_group_name(const char *u) {
/* Checks if the specified name is a valid user/group name. Also see POSIX IEEE Std 1003.1-2008, 2016 Edition,
* 3.437. We are a bit stricter here however. Specifically we deviate from POSIX rules:
*
- * - We don't allow any dots (this would break chown syntax which permits dots as user/group name separator)
* - We require that names fit into the appropriate utmp field
* - We don't allow empty user names
*
* Note that other systems are even more restrictive, and don't permit underscores or uppercase characters.
+ *
+ * jsynacek: We now allow dots in user names. The checks are not exhaustive as user names like "..." are allowed
+ * and valid according to POSIX, but can't be created using useradd. However, ".user" can be created. Let's not
+ * complicate the code by adding additional checks for weird corner cases like these, as they don't really matter here.
*/
if (isempty(u))
@@ -587,14 +590,14 @@ bool valid_user_group_name(const char *u) {
if (!(u[0] >= 'a' && u[0] <= 'z') &&
!(u[0] >= 'A' && u[0] <= 'Z') &&
- u[0] != '_')
+ u[0] != '_' && u[0] != '.')
return false;
for (i = u+1; *i; i++) {
if (!(*i >= 'a' && *i <= 'z') &&
!(*i >= 'A' && *i <= 'Z') &&
!(*i >= '0' && *i <= '9') &&
- !IN_SET(*i, '_', '-'))
+ !IN_SET(*i, '_', '-', '.'))
return false;
}
diff --git a/src/test/test-user-util.c b/src/test/test-user-util.c
index c1428fab02..9114d30b8c 100644
--- a/src/test/test-user-util.c
+++ b/src/test/test-user-util.c
@@ -71,8 +71,6 @@ static void test_valid_user_group_name(void) {
assert_se(!valid_user_group_name("-1"));
assert_se(!valid_user_group_name("-kkk"));
assert_se(!valid_user_group_name("rööt"));
- assert_se(!valid_user_group_name("."));
- assert_se(!valid_user_group_name("eff.eff"));
assert_se(!valid_user_group_name("foo\nbar"));
assert_se(!valid_user_group_name("0123456789012345678901234567890123456789"));
assert_se(!valid_user_group_name_or_id("aaa:bbb"));
@@ -83,6 +81,8 @@ static void test_valid_user_group_name(void) {
assert_se(valid_user_group_name("_kkk"));
assert_se(valid_user_group_name("kkk-"));
assert_se(valid_user_group_name("kk-k"));
+ assert_se(valid_user_group_name(".moo"));
+ assert_se(valid_user_group_name("eff.eff"));
assert_se(valid_user_group_name("some5"));
assert_se(!valid_user_group_name("5some"));
@@ -102,8 +102,6 @@ static void test_valid_user_group_name_or_id(void) {
assert_se(!valid_user_group_name_or_id("-1"));
assert_se(!valid_user_group_name_or_id("-kkk"));
assert_se(!valid_user_group_name_or_id("rööt"));
- assert_se(!valid_user_group_name_or_id("."));
- assert_se(!valid_user_group_name_or_id("eff.eff"));
assert_se(!valid_user_group_name_or_id("foo\nbar"));
assert_se(!valid_user_group_name_or_id("0123456789012345678901234567890123456789"));
assert_se(!valid_user_group_name_or_id("aaa:bbb"));
@@ -114,6 +112,8 @@ static void test_valid_user_group_name_or_id(void) {
assert_se(valid_user_group_name_or_id("_kkk"));
assert_se(valid_user_group_name_or_id("kkk-"));
assert_se(valid_user_group_name_or_id("kk-k"));
+ assert_se(valid_user_group_name_or_id(".moo"));
+ assert_se(valid_user_group_name_or_id("eff.eff"));
assert_se(valid_user_group_name_or_id("some5"));
assert_se(!valid_user_group_name_or_id("5some"));

View File

@ -0,0 +1,29 @@
From 62623bafd9ce4842122ddeda83f9527e43b9a21f Mon Sep 17 00:00:00 2001
From: Jan Synacek <jsynacek@redhat.com>
Date: Fri, 8 Nov 2019 14:54:30 +0100
Subject: [PATCH] sd-bus: bump message queue size again
Simliarly to issue #4068, the current limit turns out to be too small for a
big storage setup that uses many small disks. Let's bump it further.
(cherry picked from commit 83a32ea7b03d6707b8e5bb90a0b3a6eb868ef633)
Resolves: #1770189
---
src/libsystemd/sd-bus/bus-internal.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/libsystemd/sd-bus/bus-internal.h b/src/libsystemd/sd-bus/bus-internal.h
index 90e6028983..5d773b14c4 100644
--- a/src/libsystemd/sd-bus/bus-internal.h
+++ b/src/libsystemd/sd-bus/bus-internal.h
@@ -328,8 +328,8 @@ struct sd_bus {
* with enough entropy yet and might delay the boot */
#define BUS_AUTH_TIMEOUT ((usec_t) DEFAULT_TIMEOUT_USEC)
-#define BUS_WQUEUE_MAX (192*1024)
-#define BUS_RQUEUE_MAX (192*1024)
+#define BUS_WQUEUE_MAX (384*1024)
+#define BUS_RQUEUE_MAX (384*1024)
#define BUS_MESSAGE_SIZE_MAX (128*1024*1024)
#define BUS_AUTH_SIZE_MAX (64*1024)

View File

@ -0,0 +1,109 @@
From 18a45cf91dbdd075fb55d752f959e84d36f3ab3b Mon Sep 17 00:00:00 2001
From: Evgeny Vereshchagin <evvers@ya.ru>
Date: Fri, 7 Sep 2018 06:13:17 +0000
Subject: [PATCH] tests: put fuzz_journald_processing_function in a .c file
(cherry picked from commit 231dca5579cfba6175d19eee5347d693893fb5aa)
Resolves: #1764560
---
src/fuzz/fuzz-journald.c | 30 ++++++++++++++++++++++++++++++
src/fuzz/fuzz-journald.h | 24 ++----------------------
src/fuzz/meson.build | 6 ++++--
3 files changed, 36 insertions(+), 24 deletions(-)
create mode 100644 src/fuzz/fuzz-journald.c
diff --git a/src/fuzz/fuzz-journald.c b/src/fuzz/fuzz-journald.c
new file mode 100644
index 0000000000..f271d7f2fe
--- /dev/null
+++ b/src/fuzz/fuzz-journald.c
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "alloc-util.h"
+#include "fuzz-journald.h"
+#include "journald-server.h"
+#include "sd-event.h"
+
+void fuzz_journald_processing_function(
+ const uint8_t *data,
+ size_t size,
+ void (*f)(Server *s, const char *buf, size_t raw_len, const struct ucred *ucred, const struct timeval *tv, const char *label, size_t label_len)
+ ) {
+ Server s = {};
+ char *label = NULL;
+ size_t label_len = 0;
+ struct ucred *ucred = NULL;
+ struct timeval *tv = NULL;
+
+ if (size == 0)
+ return;
+
+ assert_se(sd_event_default(&s.event) >= 0);
+ s.syslog_fd = s.native_fd = s.stdout_fd = s.dev_kmsg_fd = s.audit_fd = s.hostname_fd = s.notify_fd = -1;
+ s.buffer = memdup_suffix0(data, size);
+ assert_se(s.buffer);
+ s.buffer_size = size + 1;
+ s.storage = STORAGE_NONE;
+ (*f)(&s, s.buffer, size, ucred, tv, label, label_len);
+ server_done(&s);
+}
diff --git a/src/fuzz/fuzz-journald.h b/src/fuzz/fuzz-journald.h
index e66ef54c9b..e9d32a74aa 100644
--- a/src/fuzz/fuzz-journald.h
+++ b/src/fuzz/fuzz-journald.h
@@ -1,30 +1,10 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-#include "alloc-util.h"
#include "journald-server.h"
-#include "sd-event.h"
-static void fuzz_journald_processing_function(
+void fuzz_journald_processing_function(
const uint8_t *data,
size_t size,
void (*f)(Server *s, const char *buf, size_t raw_len, const struct ucred *ucred, const struct timeval *tv, const char *label, size_t label_len)
- ) {
- Server s = {};
- char *label = NULL;
- size_t label_len = 0;
- struct ucred *ucred = NULL;
- struct timeval *tv = NULL;
-
- if (size == 0)
- return;
-
- assert_se(sd_event_default(&s.event) >= 0);
- s.syslog_fd = s.native_fd = s.stdout_fd = s.dev_kmsg_fd = s.audit_fd = s.hostname_fd = s.notify_fd = -1;
- s.buffer = memdup_suffix0(data, size);
- assert_se(s.buffer);
- s.buffer_size = size + 1;
- s.storage = STORAGE_NONE;
- (*f)(&s, s.buffer, size, ucred, tv, label, label_len);
- server_done(&s);
-}
+);
diff --git a/src/fuzz/meson.build b/src/fuzz/meson.build
index 483a952421..1f8631bcc0 100644
--- a/src/fuzz/meson.build
+++ b/src/fuzz/meson.build
@@ -33,12 +33,14 @@ fuzzers += [
libshared],
[libmount]],
- [['src/fuzz/fuzz-journald-native.c'],
+ [['src/fuzz/fuzz-journald-native.c',
+ 'src/fuzz/fuzz-journald.c'],
[libjournal_core,
libshared],
[libselinux]],
- [['src/fuzz/fuzz-journald-syslog.c'],
+ [['src/fuzz/fuzz-journald-syslog.c',
+ 'src/fuzz/fuzz-journald.c'],
[libjournal_core,
libshared],
[libselinux]],

View File

@ -0,0 +1,129 @@
From e7e70f575840cd021f6429f264911ae0cbff9741 Mon Sep 17 00:00:00 2001
From: Evgeny Vereshchagin <evvers@ya.ru>
Date: Thu, 15 Nov 2018 17:52:57 +0100
Subject: [PATCH] tests: add a fuzzer for dev_kmsg_record
(cherry picked from commit 8857fb9beb9dcb95a6ce1be14dc94c4dc4cd3ea3)
Resolves: #1764560
---
src/fuzz/fuzz-journald-kmsg.c | 29 +++++++++++++++++++
src/fuzz/meson.build | 5 ++++
src/journal/journald-kmsg.c | 2 +-
src/journal/journald-kmsg.h | 2 ++
test/fuzz/fuzz-journald-kmsg/basic | 1 +
test/fuzz/fuzz-journald-kmsg/dev-null | 2 ++
test/fuzz/fuzz-journald-kmsg/loopback | 2 ++
.../fuzz-journald-kmsg/subsystem-loopback | 2 ++
8 files changed, 44 insertions(+), 1 deletion(-)
create mode 100644 src/fuzz/fuzz-journald-kmsg.c
create mode 100644 test/fuzz/fuzz-journald-kmsg/basic
create mode 100644 test/fuzz/fuzz-journald-kmsg/dev-null
create mode 100644 test/fuzz/fuzz-journald-kmsg/loopback
create mode 100644 test/fuzz/fuzz-journald-kmsg/subsystem-loopback
diff --git a/src/fuzz/fuzz-journald-kmsg.c b/src/fuzz/fuzz-journald-kmsg.c
new file mode 100644
index 0000000000..5d99d244b5
--- /dev/null
+++ b/src/fuzz/fuzz-journald-kmsg.c
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "fuzz.h"
+#include "journald-kmsg.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ Server s = {};
+ _cleanup_free_ char *buffer = NULL;
+
+ if (size == 0)
+ return 0;
+
+ s = (Server) {
+ .native_fd = -1,
+ .stdout_fd = -1,
+ .dev_kmsg_fd = -1,
+ .audit_fd = -1,
+ .hostname_fd = -1,
+ .notify_fd = -1,
+ .storage = STORAGE_NONE,
+ };
+ assert_se(sd_event_default(&s.event) >= 0);
+ buffer = memdup(data, size);
+ assert_se(buffer);
+ dev_kmsg_record(&s, buffer, size);
+ server_done(&s);
+
+ return 0;
+}
diff --git a/src/fuzz/meson.build b/src/fuzz/meson.build
index 1f8631bcc0..0520e448a9 100644
--- a/src/fuzz/meson.build
+++ b/src/fuzz/meson.build
@@ -33,6 +33,11 @@ fuzzers += [
libshared],
[libmount]],
+ [['src/fuzz/fuzz-journald-kmsg.c'],
+ [libjournal_core,
+ libshared],
+ [libselinux]],
+
[['src/fuzz/fuzz-journald-native.c',
'src/fuzz/fuzz-journald.c'],
[libjournal_core,
diff --git a/src/journal/journald-kmsg.c b/src/journal/journald-kmsg.c
index 7644bebfc8..0cdf1c4794 100644
--- a/src/journal/journald-kmsg.c
+++ b/src/journal/journald-kmsg.c
@@ -93,7 +93,7 @@ static bool is_us(const char *identifier, const char *pid) {
streq(identifier, program_invocation_short_name);
}
-static void dev_kmsg_record(Server *s, char *p, size_t l) {
+void dev_kmsg_record(Server *s, char *p, size_t l) {
_cleanup_free_ char *message = NULL, *syslog_priority = NULL, *syslog_pid = NULL, *syslog_facility = NULL, *syslog_identifier = NULL, *source_time = NULL, *identifier = NULL, *pid = NULL;
struct iovec iovec[N_IOVEC_META_FIELDS + 7 + N_IOVEC_KERNEL_FIELDS + 2 + N_IOVEC_UDEV_FIELDS];
diff --git a/src/journal/journald-kmsg.h b/src/journal/journald-kmsg.h
index bff24ac310..2326bc8c93 100644
--- a/src/journal/journald-kmsg.h
+++ b/src/journal/journald-kmsg.h
@@ -9,3 +9,5 @@ int server_flush_dev_kmsg(Server *s);
void server_forward_kmsg(Server *s, int priority, const char *identifier, const char *message, const struct ucred *ucred);
int server_open_kernel_seqnum(Server *s);
+
+void dev_kmsg_record(Server *s, char *p, size_t l);
diff --git a/test/fuzz/fuzz-journald-kmsg/basic b/test/fuzz/fuzz-journald-kmsg/basic
new file mode 100644
index 0000000000..1299cd0869
--- /dev/null
+++ b/test/fuzz/fuzz-journald-kmsg/basic
@@ -0,0 +1 @@
+29,456,292891883,-;systemd[1]: Reexecuting.
diff --git a/test/fuzz/fuzz-journald-kmsg/dev-null b/test/fuzz/fuzz-journald-kmsg/dev-null
new file mode 100644
index 0000000000..de039588b5
--- /dev/null
+++ b/test/fuzz/fuzz-journald-kmsg/dev-null
@@ -0,0 +1,2 @@
+12,460,1322026586,-;hey
+ DEVICE=c1:3
diff --git a/test/fuzz/fuzz-journald-kmsg/loopback b/test/fuzz/fuzz-journald-kmsg/loopback
new file mode 100644
index 0000000000..ca320177b7
--- /dev/null
+++ b/test/fuzz/fuzz-journald-kmsg/loopback
@@ -0,0 +1,2 @@
+12,460,1322026586,-;hey
+ DEVICE=n1
diff --git a/test/fuzz/fuzz-journald-kmsg/subsystem-loopback b/test/fuzz/fuzz-journald-kmsg/subsystem-loopback
new file mode 100644
index 0000000000..af9c0d91e5
--- /dev/null
+++ b/test/fuzz/fuzz-journald-kmsg/subsystem-loopback
@@ -0,0 +1,2 @@
+12,460,1322026586,-;hey
+ DEVICE=+net:lo

View File

@ -0,0 +1,30 @@
From 43d72623fdfca8500c8c89a4b5023e35a3f0b259 Mon Sep 17 00:00:00 2001
From: Evgeny Vereshchagin <evvers@ya.ru>
Date: Fri, 16 Nov 2018 07:05:29 +0100
Subject: [PATCH] basic: remove an assertion from cunescape_one
The function takes a pointer to a random block of memory and
the length of that block. It shouldn't crash every time it sees
a zero byte at the beginning there.
This should help the dev-kmsg fuzzer to keep going.
(cherry picked from commit 8dc4de966ce6d32470aaff30ed054f6a2688d6d7)
Resolves: #1764560
---
src/basic/escape.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/basic/escape.c b/src/basic/escape.c
index 5004763d97..5f715156fb 100644
--- a/src/basic/escape.c
+++ b/src/basic/escape.c
@@ -106,7 +106,6 @@ int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit)
int r = 1;
assert(p);
- assert(*p);
assert(ret);
/* Unescapes C style. Returns the unescaped character in ret.

View File

@ -0,0 +1,25 @@
From f00d221d5dc92a530e260db5f44fa57653f03e8b Mon Sep 17 00:00:00 2001
From: Evgeny Vereshchagin <evvers@ya.ru>
Date: Fri, 16 Nov 2018 07:11:06 +0100
Subject: [PATCH] journal: fix an off-by-one error in dev_kmsg_record
(cherry picked from commit 080d112caa0dc948555a69a008c1caf4d5d41ed6)
Resolves: #1764560
---
src/journal/journald-kmsg.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/journal/journald-kmsg.c b/src/journal/journald-kmsg.c
index 0cdf1c4794..726c006ce1 100644
--- a/src/journal/journald-kmsg.c
+++ b/src/journal/journald-kmsg.c
@@ -239,7 +239,7 @@ void dev_kmsg_record(Server *s, char *p, size_t l) {
ll = udev_device_get_devlinks_list_entry(ud);
udev_list_entry_foreach(ll, ll) {
- if (j > N_IOVEC_UDEV_FIELDS)
+ if (j >= N_IOVEC_UDEV_FIELDS)
break;
g = udev_list_entry_get_name(ll);

View File

@ -0,0 +1,25 @@
From 4caa887ae8eabc087d6f9f2b233c96c220de8b02 Mon Sep 17 00:00:00 2001
From: Evgeny Vereshchagin <evvers@ya.ru>
Date: Fri, 16 Nov 2018 07:20:44 +0100
Subject: [PATCH] tests: add a reproducer for a memory leak fixed in
30eddcd51b8a472e05d3b8d1 in August
(cherry picked from commit 1dd485b700fe9ad94d7a780f14fcf18a4738ace4)
Resolves: #1764560
---
...leak-ab161e601e82f1ec31d11e2cbae2747834ce9e43 | Bin 0 -> 1847 bytes
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 test/fuzz/fuzz-journald-kmsg/leak-ab161e601e82f1ec31d11e2cbae2747834ce9e43
diff --git a/test/fuzz/fuzz-journald-kmsg/leak-ab161e601e82f1ec31d11e2cbae2747834ce9e43 b/test/fuzz/fuzz-journald-kmsg/leak-ab161e601e82f1ec31d11e2cbae2747834ce9e43
new file mode 100644
index 0000000000000000000000000000000000000000..424ae5cb010aa519758e6af90cc981795b68d3fd
GIT binary patch
literal 1847
zcmXps(lIeJ&@nVNGBPkSGqo_&(Y4M<t>jX0aSiiycD2<{NiEaQE6vG)izFLb8I!<a
b7zLvtFd70lLcjrs_^9w`2#kin;0*x)kUJOk
literal 0
HcmV?d00001

View File

@ -0,0 +1,25 @@
From 375fd5f8b3c6fb0f7c29ceb166f70bfd45314e04 Mon Sep 17 00:00:00 2001
From: Evgeny Vereshchagin <evvers@ya.ru>
Date: Fri, 16 Nov 2018 07:33:02 +0100
Subject: [PATCH] tests: add a reproducer for a heap-buffer-overflow fixed in
937b1171378bc1000a
(cherry picked from commit f7a6b40187a98751a9ab6867e8b52e4e6f1dad5c)
Resolves: #1764560
---
...crash-c6c04d83e73f3d1417bc0afce8fa81b99f955963 | Bin 0 -> 112 bytes
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 test/fuzz/fuzz-journald-kmsg/crash-c6c04d83e73f3d1417bc0afce8fa81b99f955963
diff --git a/test/fuzz/fuzz-journald-kmsg/crash-c6c04d83e73f3d1417bc0afce8fa81b99f955963 b/test/fuzz/fuzz-journald-kmsg/crash-c6c04d83e73f3d1417bc0afce8fa81b99f955963
new file mode 100644
index 0000000000000000000000000000000000000000..19887a1fec9fc29b1f7da8a2d1c5ea5054f2bc02
GIT binary patch
literal 112
zcmXpq)Zrxx80r}680lCOP-~&{)k?wIfGehgOM!tQroxI#0Z63Aa4DF?03ibx03hxS
A82|tP
literal 0
HcmV?d00001

View File

@ -0,0 +1,44 @@
From af471e7402a70b670cd50e45c6139a0ac50a74bd Mon Sep 17 00:00:00 2001
From: Evgeny Vereshchagin <evvers@ya.ru>
Date: Fri, 16 Nov 2018 09:23:53 +0100
Subject: [PATCH] test: initialize syslog_fd in fuzz-journald-kmsg too
This is a follow-up to 8857fb9beb9dcb that prevents the fuzzer from crashing with
```
==220==ERROR: AddressSanitizer: ABRT on unknown address 0x0000000000dc (pc 0x7ff4953c8428 bp 0x7ffcf66ec290 sp 0x7ffcf66ec128 T0)
SCARINESS: 10 (signal)
#0 0x7ff4953c8427 in gsignal (/lib/x86_64-linux-gnu/libc.so.6+0x35427)
#1 0x7ff4953ca029 in abort (/lib/x86_64-linux-gnu/libc.so.6+0x37029)
#2 0x7ff49666503a in log_assert_failed_realm /work/build/../../src/systemd/src/basic/log.c:805:9
#3 0x7ff496614ecf in safe_close /work/build/../../src/systemd/src/basic/fd-util.c:66:17
#4 0x548806 in server_done /work/build/../../src/systemd/src/journal/journald-server.c:2064:9
#5 0x5349fa in LLVMFuzzerTestOneInput /work/build/../../src/systemd/src/fuzz/fuzz-journald-kmsg.c:26:9
#6 0x592755 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /src/libfuzzer/FuzzerLoop.cpp:571:15
#7 0x590627 in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool*) /src/libfuzzer/FuzzerLoop.cpp:480:3
#8 0x594432 in fuzzer::Fuzzer::MutateAndTestOne() /src/libfuzzer/FuzzerLoop.cpp:708:19
#9 0x5973c6 in fuzzer::Fuzzer::Loop(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, fuzzer::fuzzer_allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&) /src/libfuzzer/FuzzerLoop.cpp:839:5
#10 0x574541 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /src/libfuzzer/FuzzerDriver.cpp:764:6
#11 0x5675fc in main /src/libfuzzer/FuzzerMain.cpp:20:10
#12 0x7ff4953b382f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
#13 0x420f58 in _start (/out/fuzz-journald-kmsg+0x420f58)
```
(cherry picked from commit cc55ac0171a2493768c021faa356513642797e7f)
Resolves: #1764560
---
src/fuzz/fuzz-journald-kmsg.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/fuzz/fuzz-journald-kmsg.c b/src/fuzz/fuzz-journald-kmsg.c
index 5d99d244b5..e2611c6d45 100644
--- a/src/fuzz/fuzz-journald-kmsg.c
+++ b/src/fuzz/fuzz-journald-kmsg.c
@@ -11,6 +11,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
return 0;
s = (Server) {
+ .syslog_fd = -1,
.native_fd = -1,
.stdout_fd = -1,
.dev_kmsg_fd = -1,

View File

@ -0,0 +1,99 @@
From f991a9c7644f3fb5155ff823600ba5a6ea403dc4 Mon Sep 17 00:00:00 2001
From: Evgeny Vereshchagin <evvers@ya.ru>
Date: Fri, 16 Nov 2018 21:23:56 +0100
Subject: [PATCH] tests: add a fuzzer for process_audit_string
(cherry picked from commit 090a20cfaf3d5439fa39c5d8df473b0cfef181dd)
Resolves: #1764560
---
src/fuzz/fuzz-journald-audit.c | 27 +++++++++++++++++++++++++++
src/fuzz/meson.build | 5 +++++
src/journal/journald-audit.c | 2 +-
src/journal/journald-audit.h | 2 ++
test/fuzz/fuzz-journald-audit/basic | 1 +
5 files changed, 36 insertions(+), 1 deletion(-)
create mode 100644 src/fuzz/fuzz-journald-audit.c
create mode 100644 test/fuzz/fuzz-journald-audit/basic
diff --git a/src/fuzz/fuzz-journald-audit.c b/src/fuzz/fuzz-journald-audit.c
new file mode 100644
index 0000000000..fe401c0d98
--- /dev/null
+++ b/src/fuzz/fuzz-journald-audit.c
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "fuzz.h"
+#include "journald-audit.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ Server s;
+ _cleanup_free_ char *buffer = NULL;
+
+ s = (Server) {
+ .syslog_fd = -1,
+ .native_fd = -1,
+ .stdout_fd = -1,
+ .dev_kmsg_fd = -1,
+ .audit_fd = -1,
+ .hostname_fd = -1,
+ .notify_fd = -1,
+ .storage = STORAGE_NONE,
+ };
+ assert_se(sd_event_default(&s.event) >= 0);
+ buffer = memdup_suffix0(data, size);
+ assert_se(buffer);
+ process_audit_string(&s, 0, buffer, size);
+ server_done(&s);
+
+ return 0;
+}
diff --git a/src/fuzz/meson.build b/src/fuzz/meson.build
index 0520e448a9..5548da3822 100644
--- a/src/fuzz/meson.build
+++ b/src/fuzz/meson.build
@@ -33,6 +33,11 @@ fuzzers += [
libshared],
[libmount]],
+ [['src/fuzz/fuzz-journald-audit.c'],
+ [libjournal_core,
+ libshared],
+ [libselinux]],
+
[['src/fuzz/fuzz-journald-kmsg.c'],
[libjournal_core,
libshared],
diff --git a/src/journal/journald-audit.c b/src/journal/journald-audit.c
index 87726684af..7810a0139a 100644
--- a/src/journal/journald-audit.c
+++ b/src/journal/journald-audit.c
@@ -313,7 +313,7 @@ static int map_all_fields(
}
}
-static void process_audit_string(Server *s, int type, const char *data, size_t size) {
+void process_audit_string(Server *s, int type, const char *data, size_t size) {
size_t n_iov_allocated = 0, n_iov = 0, z;
_cleanup_free_ struct iovec *iov = NULL;
uint64_t seconds, msec, id;
diff --git a/src/journal/journald-audit.h b/src/journal/journald-audit.h
index 57bb1711c9..7766618c98 100644
--- a/src/journal/journald-audit.h
+++ b/src/journal/journald-audit.h
@@ -6,4 +6,6 @@
void server_process_audit_message(Server *s, const void *buffer, size_t buffer_size, const struct ucred *ucred, const union sockaddr_union *sa, socklen_t salen);
+void process_audit_string(Server *s, int type, const char *data, size_t size);
+
int server_open_audit(Server*s);
diff --git a/test/fuzz/fuzz-journald-audit/basic b/test/fuzz/fuzz-journald-audit/basic
new file mode 100644
index 0000000000..d1ce8cc5f0
--- /dev/null
+++ b/test/fuzz/fuzz-journald-audit/basic
@@ -0,0 +1 @@
+audit(1542398162.211:744): pid=7376 uid=1000 auid=1000 ses=6 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 msg='op=PAM:accounting grantors=pam_unix,pam_localuser acct="vagrant" exe="/usr/bin/sudo" hostname=? addr=? terminal=/dev/pts/1 res=success'
\ No newline at end of file

View File

@ -0,0 +1,47 @@
From bef599d1a0e41afe4b6f1d6dfb6fbc86896ab8c5 Mon Sep 17 00:00:00 2001
From: Evgeny Vereshchagin <evvers@ya.ru>
Date: Fri, 16 Nov 2018 23:32:31 +0100
Subject: [PATCH] journald: check whether sscanf has changed the value
corresponding to %n
It's possible for sscanf to receive strings containing all three fields
and not matching the template at the same time. When this happens the
value of k doesn't change, which basically means that process_audit_string
tries to access memory randomly. Sometimes it works and sometimes it doesn't :-)
See also https://bugzilla.redhat.com/show_bug.cgi?id=1059314.
(cherry picked from commit 1dab14aba749b9c5ab8176c5730107b70834240b)
Resolves: #1764560
---
src/journal/journald-audit.c | 3 ++-
test/fuzz/fuzz-journald-audit/crash | 1 +
2 files changed, 3 insertions(+), 1 deletion(-)
create mode 100644 test/fuzz/fuzz-journald-audit/crash
diff --git a/src/journal/journald-audit.c b/src/journal/journald-audit.c
index 7810a0139a..0fd6ab2a84 100644
--- a/src/journal/journald-audit.c
+++ b/src/journal/journald-audit.c
@@ -341,11 +341,12 @@ void process_audit_string(Server *s, int type, const char *data, size_t size) {
if (!p)
return;
+ k = 0;
if (sscanf(p, "(%" PRIu64 ".%" PRIu64 ":%" PRIu64 "):%n",
&seconds,
&msec,
&id,
- &k) != 3)
+ &k) != 3 || k == 0)
return;
p += k;
diff --git a/test/fuzz/fuzz-journald-audit/crash b/test/fuzz/fuzz-journald-audit/crash
new file mode 100644
index 0000000000..91bd85ca6e
--- /dev/null
+++ b/test/fuzz/fuzz-journald-audit/crash
@@ -0,0 +1 @@
+audit(1542398162.211:744) pid=7376 uid=1000 auid=1000 ses=6 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 msg='op=PAM:accounting grantors=pam_unix,pam_localuser acct="vagrant" exe="/usr/bin/sudo" hostname=? addr=? terminal=/dev/pts/1 res=success'

View File

@ -0,0 +1,172 @@
From b276c85200786add6c86b6c1fedc888c71ffe5db Mon Sep 17 00:00:00 2001
From: Evgeny Vereshchagin <evvers@ya.ru>
Date: Sat, 17 Nov 2018 13:01:09 +0100
Subject: [PATCH] tests: introduce dummy_server_init and use it in all journald
fuzzers
(cherry picked from commit ed62712dc6fb236845c489a7f386c7aff0ec31d6)
Resolves: #1764560
---
src/fuzz/fuzz-journald-audit.c | 18 +++---------------
src/fuzz/fuzz-journald-kmsg.c | 20 ++++----------------
src/fuzz/fuzz-journald.c | 26 +++++++++++++++++++-------
src/fuzz/fuzz-journald.h | 2 ++
src/fuzz/meson.build | 6 ++++--
5 files changed, 32 insertions(+), 40 deletions(-)
diff --git a/src/fuzz/fuzz-journald-audit.c b/src/fuzz/fuzz-journald-audit.c
index fe401c0d98..3f3ce7e8ee 100644
--- a/src/fuzz/fuzz-journald-audit.c
+++ b/src/fuzz/fuzz-journald-audit.c
@@ -1,26 +1,14 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#include "fuzz.h"
+#include "fuzz-journald.h"
#include "journald-audit.h"
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
Server s;
- _cleanup_free_ char *buffer = NULL;
- s = (Server) {
- .syslog_fd = -1,
- .native_fd = -1,
- .stdout_fd = -1,
- .dev_kmsg_fd = -1,
- .audit_fd = -1,
- .hostname_fd = -1,
- .notify_fd = -1,
- .storage = STORAGE_NONE,
- };
- assert_se(sd_event_default(&s.event) >= 0);
- buffer = memdup_suffix0(data, size);
- assert_se(buffer);
- process_audit_string(&s, 0, buffer, size);
+ dummy_server_init(&s, data, size);
+ process_audit_string(&s, 0, s.buffer, size);
server_done(&s);
return 0;
diff --git a/src/fuzz/fuzz-journald-kmsg.c b/src/fuzz/fuzz-journald-kmsg.c
index e2611c6d45..f7426c8400 100644
--- a/src/fuzz/fuzz-journald-kmsg.c
+++ b/src/fuzz/fuzz-journald-kmsg.c
@@ -1,29 +1,17 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#include "fuzz.h"
+#include "fuzz-journald.h"
#include "journald-kmsg.h"
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
- Server s = {};
- _cleanup_free_ char *buffer = NULL;
+ Server s;
if (size == 0)
return 0;
- s = (Server) {
- .syslog_fd = -1,
- .native_fd = -1,
- .stdout_fd = -1,
- .dev_kmsg_fd = -1,
- .audit_fd = -1,
- .hostname_fd = -1,
- .notify_fd = -1,
- .storage = STORAGE_NONE,
- };
- assert_se(sd_event_default(&s.event) >= 0);
- buffer = memdup(data, size);
- assert_se(buffer);
- dev_kmsg_record(&s, buffer, size);
+ dummy_server_init(&s, data, size);
+ dev_kmsg_record(&s, s.buffer, size);
server_done(&s);
return 0;
diff --git a/src/fuzz/fuzz-journald.c b/src/fuzz/fuzz-journald.c
index f271d7f2fe..0659b92ba3 100644
--- a/src/fuzz/fuzz-journald.c
+++ b/src/fuzz/fuzz-journald.c
@@ -5,12 +5,29 @@
#include "journald-server.h"
#include "sd-event.h"
+void dummy_server_init(Server *s, const uint8_t *buffer, size_t size) {
+ *s = (Server) {
+ .syslog_fd = -1,
+ .native_fd = -1,
+ .stdout_fd = -1,
+ .dev_kmsg_fd = -1,
+ .audit_fd = -1,
+ .hostname_fd = -1,
+ .notify_fd = -1,
+ .storage = STORAGE_NONE,
+ };
+ assert_se(sd_event_default(&s->event) >= 0);
+ s->buffer = memdup_suffix0(buffer, size);
+ assert_se(s->buffer);
+ s->buffer_size = size + 1;
+}
+
void fuzz_journald_processing_function(
const uint8_t *data,
size_t size,
void (*f)(Server *s, const char *buf, size_t raw_len, const struct ucred *ucred, const struct timeval *tv, const char *label, size_t label_len)
) {
- Server s = {};
+ Server s;
char *label = NULL;
size_t label_len = 0;
struct ucred *ucred = NULL;
@@ -19,12 +36,7 @@ void fuzz_journald_processing_function(
if (size == 0)
return;
- assert_se(sd_event_default(&s.event) >= 0);
- s.syslog_fd = s.native_fd = s.stdout_fd = s.dev_kmsg_fd = s.audit_fd = s.hostname_fd = s.notify_fd = -1;
- s.buffer = memdup_suffix0(data, size);
- assert_se(s.buffer);
- s.buffer_size = size + 1;
- s.storage = STORAGE_NONE;
+ dummy_server_init(&s, data, size);
(*f)(&s, s.buffer, size, ucred, tv, label, label_len);
server_done(&s);
}
diff --git a/src/fuzz/fuzz-journald.h b/src/fuzz/fuzz-journald.h
index e9d32a74aa..77e3b0c064 100644
--- a/src/fuzz/fuzz-journald.h
+++ b/src/fuzz/fuzz-journald.h
@@ -3,6 +3,8 @@
#include "journald-server.h"
+void dummy_server_init(Server *s, const uint8_t *buffer, size_t size);
+
void fuzz_journald_processing_function(
const uint8_t *data,
size_t size,
diff --git a/src/fuzz/meson.build b/src/fuzz/meson.build
index 5548da3822..897c02e4ae 100644
--- a/src/fuzz/meson.build
+++ b/src/fuzz/meson.build
@@ -33,12 +33,14 @@ fuzzers += [
libshared],
[libmount]],
- [['src/fuzz/fuzz-journald-audit.c'],
+ [['src/fuzz/fuzz-journald-audit.c',
+ 'src/fuzz/fuzz-journald.c'],
[libjournal_core,
libshared],
[libselinux]],
- [['src/fuzz/fuzz-journald-kmsg.c'],
+ [['src/fuzz/fuzz-journald-kmsg.c',
+ 'src/fuzz/fuzz-journald.c'],
[libjournal_core,
libshared],
[libselinux]],

View File

@ -0,0 +1,148 @@
From e7077e3a551a3faedfcc3d007de6a72fb5e1df62 Mon Sep 17 00:00:00 2001
From: Evgeny Vereshchagin <evvers@ya.ru>
Date: Tue, 20 Nov 2018 01:20:32 +0100
Subject: [PATCH] tests: add a fuzzer for journald streams
(cherry picked from commit 9541f5ff5c637bb1b3e3c69706cb73e68ff06813)
Resolves: #1764560
---
src/fuzz/fuzz-journald-stream.c | 35 ++++++++++++++++++++++++++++
src/fuzz/fuzz-journald.c | 10 +++++---
src/fuzz/meson.build | 6 +++++
src/journal/journald-stream.c | 4 ++--
src/journal/journald-stream.h | 2 ++
test/fuzz/fuzz-journald-stream/basic | 8 +++++++
6 files changed, 60 insertions(+), 5 deletions(-)
create mode 100644 src/fuzz/fuzz-journald-stream.c
create mode 100644 test/fuzz/fuzz-journald-stream/basic
diff --git a/src/fuzz/fuzz-journald-stream.c b/src/fuzz/fuzz-journald-stream.c
new file mode 100644
index 0000000000..247c0889bc
--- /dev/null
+++ b/src/fuzz/fuzz-journald-stream.c
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <linux/sockios.h>
+
+#include "fd-util.h"
+#include "fuzz.h"
+#include "fuzz-journald.h"
+#include "journald-stream.h"
+
+static int stream_fds[2] = { -1, -1 };
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ Server s;
+ StdoutStream *stream;
+ int v;
+
+ if (size == 0)
+ return 0;
+
+ if (!getenv("SYSTEMD_LOG_LEVEL"))
+ log_set_max_level(LOG_CRIT);
+
+ assert_se(socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0, stream_fds) >= 0);
+ dummy_server_init(&s, NULL, 0);
+ assert_se(stdout_stream_install(&s, stream_fds[0], &stream) >= 0);
+ assert_se(write(stream_fds[1], data, size) == (ssize_t) size);
+ while (ioctl(stream_fds[0], SIOCINQ, &v) == 0 && v)
+ sd_event_run(s.event, (uint64_t) -1);
+ if (s.n_stdout_streams)
+ stdout_stream_destroy(stream);
+ server_done(&s);
+ stream_fds[1] = safe_close(stream_fds[1]);
+
+ return 0;
+}
diff --git a/src/fuzz/fuzz-journald.c b/src/fuzz/fuzz-journald.c
index 0659b92ba3..950e885cae 100644
--- a/src/fuzz/fuzz-journald.c
+++ b/src/fuzz/fuzz-journald.c
@@ -15,11 +15,15 @@ void dummy_server_init(Server *s, const uint8_t *buffer, size_t size) {
.hostname_fd = -1,
.notify_fd = -1,
.storage = STORAGE_NONE,
+ .line_max = 64,
};
assert_se(sd_event_default(&s->event) >= 0);
- s->buffer = memdup_suffix0(buffer, size);
- assert_se(s->buffer);
- s->buffer_size = size + 1;
+
+ if (buffer) {
+ s->buffer = memdup_suffix0(buffer, size);
+ assert_se(s->buffer);
+ s->buffer_size = size + 1;
+ }
}
void fuzz_journald_processing_function(
diff --git a/src/fuzz/meson.build b/src/fuzz/meson.build
index 897c02e4ae..eea9117360 100644
--- a/src/fuzz/meson.build
+++ b/src/fuzz/meson.build
@@ -51,6 +51,12 @@ fuzzers += [
libshared],
[libselinux]],
+ [['src/fuzz/fuzz-journald-stream.c',
+ 'src/fuzz/fuzz-journald.c'],
+ [libjournal_core,
+ libshared],
+ [libselinux]],
+
[['src/fuzz/fuzz-journald-syslog.c',
'src/fuzz/fuzz-journald.c'],
[libjournal_core,
diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c
index dbf3503a82..6f8a4011ff 100644
--- a/src/journal/journald-stream.c
+++ b/src/journal/journald-stream.c
@@ -125,7 +125,7 @@ void stdout_stream_free(StdoutStream *s) {
DEFINE_TRIVIAL_CLEANUP_FUNC(StdoutStream*, stdout_stream_free);
-static void stdout_stream_destroy(StdoutStream *s) {
+void stdout_stream_destroy(StdoutStream *s) {
if (!s)
return;
@@ -534,7 +534,7 @@ terminate:
return 0;
}
-static int stdout_stream_install(Server *s, int fd, StdoutStream **ret) {
+int stdout_stream_install(Server *s, int fd, StdoutStream **ret) {
_cleanup_(stdout_stream_freep) StdoutStream *stream = NULL;
sd_id128_t id;
int r;
diff --git a/src/journal/journald-stream.h b/src/journal/journald-stream.h
index bc5622ab3b..487376e763 100644
--- a/src/journal/journald-stream.h
+++ b/src/journal/journald-stream.h
@@ -10,4 +10,6 @@ int server_open_stdout_socket(Server *s);
int server_restore_streams(Server *s, FDSet *fds);
void stdout_stream_free(StdoutStream *s);
+int stdout_stream_install(Server *s, int fd, StdoutStream **ret);
+void stdout_stream_destroy(StdoutStream *s);
void stdout_stream_send_notify(StdoutStream *s);
diff --git a/test/fuzz/fuzz-journald-stream/basic b/test/fuzz/fuzz-journald-stream/basic
new file mode 100644
index 0000000000..a088f1a539
--- /dev/null
+++ b/test/fuzz/fuzz-journald-stream/basic
@@ -0,0 +1,8 @@
+
+
+6
+1
+0
+0
+0
+hey
\ No newline at end of file

View File

@ -0,0 +1,96 @@
From 76e2fa8ed4bbee7c625e3b790f2e38a59fffd93d Mon Sep 17 00:00:00 2001
From: Evgeny Vereshchagin <evvers@ya.ru>
Date: Fri, 23 Nov 2018 00:27:19 +0100
Subject: [PATCH] tests: add a fuzzer for server_process_native_file
(cherry picked from commit a4aa59bae206eebb4703b291147144def5d4bb3e)
Resolves: #1764560
---
src/fuzz/fuzz-journald-native-fd.c | 47 ++++++++++++++++++++++++
src/fuzz/meson.build | 6 +++
test/fuzz/fuzz-journald-native-fd/basic | Bin 0 -> 34 bytes
3 files changed, 53 insertions(+)
create mode 100644 src/fuzz/fuzz-journald-native-fd.c
create mode 100644 test/fuzz/fuzz-journald-native-fd/basic
diff --git a/src/fuzz/fuzz-journald-native-fd.c b/src/fuzz/fuzz-journald-native-fd.c
new file mode 100644
index 0000000000..95415d9f85
--- /dev/null
+++ b/src/fuzz/fuzz-journald-native-fd.c
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
+#include "fuzz.h"
+#include "fuzz-journald.h"
+#include "journald-native.h"
+#include "memfd-util.h"
+#include "process-util.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ Server s;
+ _cleanup_close_ int sealed_fd = -1, unsealed_fd = -1;
+ _cleanup_(unlink_tempfilep) char name[] = "/tmp/fuzz-journald-native-fd.XXXXXX";
+ char *label = NULL;
+ size_t label_len = 0;
+ struct ucred ucred;
+ struct timeval *tv = NULL;
+
+ if (!getenv("SYSTEMD_LOG_LEVEL"))
+ log_set_max_level(LOG_CRIT);
+
+ dummy_server_init(&s, NULL, 0);
+
+ sealed_fd = memfd_new(NULL);
+ assert_se(sealed_fd >= 0);
+ assert_se(write(sealed_fd, data, size) == (ssize_t) size);
+ assert_se(memfd_set_sealed(sealed_fd) >= 0);
+ assert_se(lseek(sealed_fd, 0, SEEK_SET) == 0);
+ ucred = (struct ucred) {
+ .pid = getpid_cached(),
+ .uid = geteuid(),
+ .gid = getegid(),
+ };
+ server_process_native_file(&s, sealed_fd, &ucred, tv, label, label_len);
+
+ unsealed_fd = mkostemp_safe(name);
+ assert_se(unsealed_fd >= 0);
+ assert_se(write(unsealed_fd, data, size) == (ssize_t) size);
+ assert_se(lseek(unsealed_fd, 0, SEEK_SET) == 0);
+ server_process_native_file(&s, unsealed_fd, &ucred, tv, label, label_len);
+
+ server_done(&s);
+
+ return 0;
+}
diff --git a/src/fuzz/meson.build b/src/fuzz/meson.build
index eea9117360..5315d2771c 100644
--- a/src/fuzz/meson.build
+++ b/src/fuzz/meson.build
@@ -51,6 +51,12 @@ fuzzers += [
libshared],
[libselinux]],
+ [['src/fuzz/fuzz-journald-native-fd.c',
+ 'src/fuzz/fuzz-journald.c'],
+ [libjournal_core,
+ libshared],
+ [libselinux]],
+
[['src/fuzz/fuzz-journald-stream.c',
'src/fuzz/fuzz-journald.c'],
[libjournal_core,
diff --git a/test/fuzz/fuzz-journald-native-fd/basic b/test/fuzz/fuzz-journald-native-fd/basic
new file mode 100644
index 0000000000000000000000000000000000000000..65f89705a655618851c0e446efaa5c633adf425f
GIT binary patch
literal 34
kcmeZu4Gwm6cjaPXfB;7>M@KGyCofm$koW*k7h3}^0B8*cRR910
literal 0
HcmV?d00001

View File

@ -0,0 +1,47 @@
From 2d197adc6d7109d5901401a90288530582f3f991 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Tue, 26 Feb 2019 13:00:35 +0100
Subject: [PATCH] fuzz-journal-stream: avoid assertion failure on samples which
don't fit in pipe
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Fixes https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=11587.
We had a sample which was large enough that write(2) failed to push all the
data into the pipe, and an assert failed. The code could be changed to use
a loop, but then we'd need to interleave writes and sd_event_run (to process
the journal). I don't think the complexity is worth it — fuzzing works best
if the sample is not too huge anyway. So let's just reject samples above 64k,
and tell oss-fuzz about this limit.
(cherry picked from commit eafadd069c4e30ed62173123326a7237448615d1)
Resolves: #1764560
---
src/fuzz/fuzz-journald-stream.c | 2 +-
src/fuzz/fuzz-journald-stream.options | 2 ++
2 files changed, 3 insertions(+), 1 deletion(-)
create mode 100644 src/fuzz/fuzz-journald-stream.options
diff --git a/src/fuzz/fuzz-journald-stream.c b/src/fuzz/fuzz-journald-stream.c
index 247c0889bc..693b197d3a 100644
--- a/src/fuzz/fuzz-journald-stream.c
+++ b/src/fuzz/fuzz-journald-stream.c
@@ -14,7 +14,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
StdoutStream *stream;
int v;
- if (size == 0)
+ if (size == 0 || size > 65536)
return 0;
if (!getenv("SYSTEMD_LOG_LEVEL"))
diff --git a/src/fuzz/fuzz-journald-stream.options b/src/fuzz/fuzz-journald-stream.options
new file mode 100644
index 0000000000..678d526b1e
--- /dev/null
+++ b/src/fuzz/fuzz-journald-stream.options
@@ -0,0 +1,2 @@
+[libfuzzer]
+max_len = 65536

View File

@ -0,0 +1,45 @@
From 3521217c88b364e2c5b10a1e35d3c036b1ecba64 Mon Sep 17 00:00:00 2001
From: Evgeny Vereshchagin <evvers@ya.ru>
Date: Fri, 10 Aug 2018 12:55:09 +0000
Subject: [PATCH] journald: take leading spaces into account in
syslog_parse_identifier
This is a kind of follow-up to e88baee88fad8bc59d3 which should finally fix
the issue which that commit was supposed to fix.
(cherry picked from commit 937b1171378bc1000a34fcdfe9534d898227e35f)
Resolves: #1764560
---
src/journal/journald-syslog.c | 3 ++-
src/journal/test-journal-syslog.c | 2 ++
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/src/journal/journald-syslog.c b/src/journal/journald-syslog.c
index e0b55cc566..ae966763a0 100644
--- a/src/journal/journald-syslog.c
+++ b/src/journal/journald-syslog.c
@@ -223,8 +223,9 @@ size_t syslog_parse_identifier(const char **buf, char **identifier, char **pid)
if (p[e] != '\0' && strchr(WHITESPACE, p[e]))
e++;
+ l = (p - *buf) + e;
*buf = p + e;
- return e;
+ return l;
}
static void syslog_skip_date(char **buf) {
diff --git a/src/journal/test-journal-syslog.c b/src/journal/test-journal-syslog.c
index 120477cc9f..415b9d23ca 100644
--- a/src/journal/test-journal-syslog.c
+++ b/src/journal/test-journal-syslog.c
@@ -41,6 +41,8 @@ int main(void) {
test_syslog_parse_identifier(" ", NULL, NULL, " ", 0);
test_syslog_parse_identifier(":", "", NULL, "", 1);
test_syslog_parse_identifier(": ", "", NULL, " ", 2);
+ test_syslog_parse_identifier(" :", "", NULL, "", 2);
+ test_syslog_parse_identifier(" pidu:", "pidu", NULL, "", 8);
test_syslog_parse_identifier("pidu:", "pidu", NULL, "", 5);
test_syslog_parse_identifier("pidu: ", "pidu", NULL, "", 6);
test_syslog_parse_identifier("pidu : ", NULL, NULL, "pidu : ", 0);

View File

@ -0,0 +1,43 @@
From 5df63c2ddf93bab5e7f13e09dfb1f97a011b3451 Mon Sep 17 00:00:00 2001
From: Taro Yamada <archer_ame@yahoo.co.jp>
Date: Sun, 27 Jan 2019 13:50:04 +0900
Subject: [PATCH] Add a warning about the difference in permissions between
existing directories and unit settings.
To follows the intent of 30c81ce, this change does not execute chmod() and just add warnings.
(cherry picked from commit 6cff72eb0a18d8547f005a481cd0622d3bc78483)
Related: #1778384
---
src/core/execute.c | 17 +++++++++++++++--
1 file changed, 15 insertions(+), 2 deletions(-)
diff --git a/src/core/execute.c b/src/core/execute.c
index 8293c522bc..9ddba00421 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -2099,8 +2099,21 @@ static int setup_exec_directory(
r = mkdir_label(p, context->directories[type].mode);
if (r < 0 && r != -EEXIST)
goto fail;
- if (r == -EEXIST && !context->dynamic_user)
- continue;
+ if (r == -EEXIST) {
+ struct stat st;
+
+ if (stat(p, &st) < 0) {
+ r = -errno;
+ goto fail;
+ }
+ if (((st.st_mode ^ context->directories[type].mode) & 07777) != 0)
+ log_warning("%s \'%s\' already exists but the mode is different. "
+ "(filesystem: %o %sMode: %o)",
+ exec_directory_type_to_string(type), *rt,
+ st.st_mode & 07777, exec_directory_type_to_string(type), context->directories[type].mode & 07777);
+ if (!context->dynamic_user)
+ continue;
+ }
}
/* Don't change the owner of the configuration directory, as in the common case it is not written to by

View File

@ -0,0 +1,32 @@
From 81ca39b7b38ef1d44cc146efe75bef412e7c4c97 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Thu, 14 Mar 2019 17:01:46 +0100
Subject: [PATCH] execute: remove one redundant comparison check
(cherry picked from commit d484580ca6f0e79abe6f3f5c677323a22d9e22d7)
Related: #1778384
---
src/core/execute.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/src/core/execute.c b/src/core/execute.c
index 9ddba00421..46aa733937 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -2097,11 +2097,12 @@ static int setup_exec_directory(
}
} else {
r = mkdir_label(p, context->directories[type].mode);
- if (r < 0 && r != -EEXIST)
- goto fail;
- if (r == -EEXIST) {
+ if (r < 0) {
struct stat st;
+ if (r != -EEXIST)
+ goto fail;
+
if (stat(p, &st) < 0) {
r = -errno;
goto fail;

View File

@ -0,0 +1,88 @@
From 789806ac06bb13d1b579fef47dbb85f224b6dbb1 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Thu, 14 Mar 2019 17:19:30 +0100
Subject: [PATCH] core: change ownership/mode of the execution directories also
for static users
It's probably unexpected if we do a recursive chown() when dynamic users
are used but not on static users.
hence, let's tweak the logic slightly, and recursively chown in both
cases, except when operating on the configuration directory.
Fixes: #11842
(cherry picked from commit 206e9864de460dd79d9edd7bedb47dee168765e1)
Resolves: #1778384
---
src/core/execute.c | 47 +++++++++++++++++++++++++---------------------
1 file changed, 26 insertions(+), 21 deletions(-)
diff --git a/src/core/execute.c b/src/core/execute.c
index 46aa733937..c42300a41e 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -2090,37 +2090,42 @@ static int setup_exec_directory(
if (r < 0)
goto fail;
- /* Lock down the access mode */
- if (chmod(pp, context->directories[type].mode) < 0) {
- r = -errno;
- goto fail;
- }
} else {
r = mkdir_label(p, context->directories[type].mode);
if (r < 0) {
- struct stat st;
-
if (r != -EEXIST)
goto fail;
- if (stat(p, &st) < 0) {
- r = -errno;
- goto fail;
- }
- if (((st.st_mode ^ context->directories[type].mode) & 07777) != 0)
- log_warning("%s \'%s\' already exists but the mode is different. "
- "(filesystem: %o %sMode: %o)",
- exec_directory_type_to_string(type), *rt,
- st.st_mode & 07777, exec_directory_type_to_string(type), context->directories[type].mode & 07777);
- if (!context->dynamic_user)
+ if (type == EXEC_DIRECTORY_CONFIGURATION) {
+ struct stat st;
+
+ /* Don't change the owner/access mode of the configuration directory,
+ * as in the common case it is not written to by a service, and shall
+ * not be writable. */
+
+ if (stat(p, &st) < 0) {
+ r = -errno;
+ goto fail;
+ }
+
+ /* Still complain if the access mode doesn't match */
+ if (((st.st_mode ^ context->directories[type].mode) & 07777) != 0)
+ log_warning("%s \'%s\' already exists but the mode is different. "
+ "(File system: %o %sMode: %o)",
+ exec_directory_type_to_string(type), *rt,
+ st.st_mode & 07777, exec_directory_type_to_string(type), context->directories[type].mode & 07777);
+
continue;
+ }
}
}
- /* Don't change the owner of the configuration directory, as in the common case it is not written to by
- * a service, and shall not be writable. */
- if (type == EXEC_DIRECTORY_CONFIGURATION)
- continue;
+ /* Lock down the access mode (we use chmod_and_chown() to make this idempotent. We don't
+ * specifiy UID/GID here, so that path_chown_recursive() can optimize things depending on the
+ * current UID/GID ownership.) */
+ r = chmod_and_chown(pp ?: p, context->directories[type].mode, UID_INVALID, GID_INVALID);
+ if (r < 0)
+ goto fail;
/* Then, change the ownership of the whole tree, if necessary */
r = path_chown_recursive(pp ?: p, uid, gid);

View File

@ -0,0 +1,25 @@
From 5d7e8cb0e12e4642a760cf00cbb6caf4c07b9cd9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Sun, 19 May 2019 16:05:02 +0200
Subject: [PATCH] core/dbus-execute: remove unnecessary initialization
(cherry picked from commit bd0abfaea1514bdd7cb60228d7a3f94c17ba916d)
Related: #1734787
---
src/core/dbus-execute.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
index 33a91c012e..5379545d57 100644
--- a/src/core/dbus-execute.c
+++ b/src/core/dbus-execute.c
@@ -1552,7 +1552,7 @@ int bus_exec_context_set_transient_property(
#endif
if (streq(name, "CPUAffinity")) {
const void *a;
- size_t n = 0;
+ size_t n;
r = sd_bus_message_read_array(message, 'y', &a, &n);
if (r < 0)

View File

@ -0,0 +1,215 @@
From 46b4d26c54a773f7da350e89562039ccc5157a8f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Sun, 19 May 2019 18:02:38 +0200
Subject: [PATCH] shared/cpu-set-util: move the part to print cpu-set into a
separate function
Also avoid unnecessary asprintf() when we can write to the output area
directly.
(cherry picked from commit a832893f9c4f0a0329768e90f67e2fa24bb0008e)
Related: #1734787
---
src/basic/cpu-set-util.c | 21 +++++++++++++++++++++
src/basic/cpu-set-util.h | 1 +
src/core/dbus-execute.c | 29 +++++------------------------
src/test/test-cpu-set-util.c | 29 +++++++++++++++++++++++++++++
4 files changed, 56 insertions(+), 24 deletions(-)
diff --git a/src/basic/cpu-set-util.c b/src/basic/cpu-set-util.c
index b1c927bcb8..8f24a2601a 100644
--- a/src/basic/cpu-set-util.c
+++ b/src/basic/cpu-set-util.c
@@ -5,6 +5,7 @@
#include <errno.h>
#include <stddef.h>
+#include <stdio.h>
#include <syslog.h>
#include "alloc-util.h"
@@ -15,6 +16,26 @@
#include "parse-util.h"
#include "string-util.h"
+char* cpu_set_to_string(const cpu_set_t *set, size_t setsize) {
+ _cleanup_free_ char *str = NULL;
+ size_t allocated = 0, len = 0;
+ int i, r;
+
+ for (i = 0; (size_t) i < setsize * 8; i++) {
+ if (!CPU_ISSET_S(i, setsize, set))
+ continue;
+
+ if (!GREEDY_REALLOC(str, allocated, len + 1 + DECIMAL_STR_MAX(int)))
+ return NULL;
+
+ r = sprintf(str + len, len > 0 ? " %d" : "%d", i);
+ assert_se(r > 0);
+ len += r;
+ }
+
+ return TAKE_PTR(str) ?: strdup("");
+}
+
cpu_set_t* cpu_set_malloc(unsigned *ncpus) {
cpu_set_t *c;
unsigned n = 1024;
diff --git a/src/basic/cpu-set-util.h b/src/basic/cpu-set-util.h
index 88470fe15a..3c546beb55 100644
--- a/src/basic/cpu-set-util.h
+++ b/src/basic/cpu-set-util.h
@@ -26,6 +26,7 @@ static inline cpu_set_t* cpu_set_mfree(cpu_set_t *p) {
cpu_set_t* cpu_set_malloc(unsigned *ncpus);
+char* cpu_set_to_string(const cpu_set_t *set, size_t setsize);
int parse_cpu_set_internal(const char *rvalue, cpu_set_t **cpu_set, bool warn, const char *unit, const char *filename, unsigned line, const char *lvalue);
static inline int parse_cpu_set_and_warn(const char *rvalue, cpu_set_t **cpu_set, const char *unit, const char *filename, unsigned line, const char *lvalue) {
diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
index 5379545d57..d9f4445745 100644
--- a/src/core/dbus-execute.c
+++ b/src/core/dbus-execute.c
@@ -1565,32 +1565,13 @@ int bus_exec_context_set_transient_property(
unit_write_settingf(u, flags, name, "%s=", name);
} else {
_cleanup_free_ char *str = NULL;
- size_t allocated = 0, len = 0, i, ncpus;
+ size_t ncpus;
- ncpus = CPU_SIZE_TO_NUM(n);
-
- for (i = 0; i < ncpus; i++) {
- _cleanup_free_ char *p = NULL;
- size_t add;
-
- if (!CPU_ISSET_S(i, n, (cpu_set_t*) a))
- continue;
-
- r = asprintf(&p, "%zu", i);
- if (r < 0)
- return -ENOMEM;
-
- add = strlen(p);
-
- if (!GREEDY_REALLOC(str, allocated, len + add + 2))
- return -ENOMEM;
-
- strcpy(mempcpy(str + len, p, add), " ");
- len += add + 1;
- }
+ str = cpu_set_to_string(a, n);
+ if (!str)
+ return -ENOMEM;
- if (len != 0)
- str[len - 1] = '\0';
+ ncpus = CPU_SIZE_TO_NUM(n);
if (!c->cpuset || c->cpuset_ncpus < ncpus) {
cpu_set_t *cpuset;
diff --git a/src/test/test-cpu-set-util.c b/src/test/test-cpu-set-util.c
index c9272459b4..ff5edb2a69 100644
--- a/src/test/test-cpu-set-util.c
+++ b/src/test/test-cpu-set-util.c
@@ -6,6 +6,7 @@
static void test_parse_cpu_set(void) {
cpu_set_t *c = NULL;
+ _cleanup_free_ char *str = NULL;
int ncpus;
int cpu;
@@ -15,6 +16,10 @@ static void test_parse_cpu_set(void) {
assert_se(CPU_ISSET_S(1, CPU_ALLOC_SIZE(ncpus), c));
assert_se(CPU_ISSET_S(2, CPU_ALLOC_SIZE(ncpus), c));
assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 2);
+
+ assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus)));
+ log_info("cpu_set_to_string: %s", str);
+ str = mfree(str);
c = cpu_set_mfree(c);
/* A more interesting range */
@@ -25,6 +30,9 @@ static void test_parse_cpu_set(void) {
assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
for (cpu = 8; cpu < 12; cpu++)
assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
+ assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus)));
+ log_info("cpu_set_to_string: %s", str);
+ str = mfree(str);
c = cpu_set_mfree(c);
/* Quoted strings */
@@ -33,6 +41,9 @@ static void test_parse_cpu_set(void) {
assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 4);
for (cpu = 8; cpu < 12; cpu++)
assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
+ assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus)));
+ log_info("cpu_set_to_string: %s", str);
+ str = mfree(str);
c = cpu_set_mfree(c);
/* Use commas as separators */
@@ -43,6 +54,9 @@ static void test_parse_cpu_set(void) {
assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
for (cpu = 8; cpu < 12; cpu++)
assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
+ assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus)));
+ log_info("cpu_set_to_string: %s", str);
+ str = mfree(str);
c = cpu_set_mfree(c);
/* Commas with spaces (and trailing comma, space) */
@@ -51,6 +65,9 @@ static void test_parse_cpu_set(void) {
assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8);
for (cpu = 0; cpu < 8; cpu++)
assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
+ assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus)));
+ log_info("cpu_set_to_string: %s", str);
+ str = mfree(str);
c = cpu_set_mfree(c);
/* Ranges */
@@ -61,6 +78,9 @@ static void test_parse_cpu_set(void) {
assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
for (cpu = 8; cpu < 12; cpu++)
assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
+ assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus)));
+ log_info("cpu_set_to_string: %s", str);
+ str = mfree(str);
c = cpu_set_mfree(c);
/* Ranges with trailing comma, space */
@@ -71,6 +91,9 @@ static void test_parse_cpu_set(void) {
assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
for (cpu = 8; cpu < 12; cpu++)
assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
+ assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus)));
+ log_info("cpu_set_to_string: %s", str);
+ str = mfree(str);
c = cpu_set_mfree(c);
/* Negative range (returns empty cpu_set) */
@@ -85,6 +108,9 @@ static void test_parse_cpu_set(void) {
assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 12);
for (cpu = 0; cpu < 12; cpu++)
assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
+ assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus)));
+ log_info("cpu_set_to_string: %s", str);
+ str = mfree(str);
c = cpu_set_mfree(c);
/* Mix ranges and individual CPUs */
@@ -95,6 +121,9 @@ static void test_parse_cpu_set(void) {
assert_se(CPU_ISSET_S(1, CPU_ALLOC_SIZE(ncpus), c));
for (cpu = 4; cpu < 12; cpu++)
assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
+ assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus)));
+ log_info("cpu_set_to_string: %s", str);
+ str = mfree(str);
c = cpu_set_mfree(c);
/* Garbage */

View File

@ -0,0 +1,29 @@
From d6935e61de30967aa82b7722f36193ba782b75e4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Sun, 19 May 2019 18:08:39 +0200
Subject: [PATCH] shared/cpu-set-util: remove now-unused CPU_SIZE_TO_NUM()
(cherry picked from commit b12ef7141648be40fd8c4b0209a742f2151736d9)
Related: #1734787
---
src/basic/cpu-set-util.h | 6 ------
1 file changed, 6 deletions(-)
diff --git a/src/basic/cpu-set-util.h b/src/basic/cpu-set-util.h
index 3c546beb55..20612a8876 100644
--- a/src/basic/cpu-set-util.h
+++ b/src/basic/cpu-set-util.h
@@ -9,12 +9,6 @@
#include "macro.h"
-#ifdef __NCPUBITS
-#define CPU_SIZE_TO_NUM(n) ((n) * __NCPUBITS)
-#else
-#define CPU_SIZE_TO_NUM(n) ((n) * sizeof(cpu_set_t) * 8)
-#endif
-
DEFINE_TRIVIAL_CLEANUP_FUNC(cpu_set_t*, CPU_FREE);
#define _cleanup_cpu_free_ _cleanup_(CPU_FREEp)

View File

@ -0,0 +1,932 @@
From 61e5aed87f1b82a51c6ea8ccde96805cb63e5b15 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Tue, 21 May 2019 08:45:19 +0200
Subject: [PATCH] Rework cpu affinity parsing
The CPU_SET_S api is pretty bad. In particular, it has a parameter for the size
of the array, but operations which take two (CPU_EQUAL_S) or even three arrays
(CPU_{AND,OR,XOR}_S) still take just one size. This means that all arrays must
be of the same size, or buffer overruns will occur. This is exactly what our
code would do, if it received an array of unexpected size over the network.
("Unexpected" here means anything different from what cpu_set_malloc() detects
as the "right" size.)
Let's rework this, and store the size in bytes of the allocated storage area.
The code will now parse any number up to 8191, independently of what the current
kernel supports. This matches the kernel maximum setting for any architecture,
to make things more portable.
Fixes #12605.
(cherry picked from commit 0985c7c4e22c8dbbea4398cf3453da45ebf63800)
Related: #1734787
---
src/basic/cpu-set-util.c | 133 +++++++++++++++++++++-----
src/basic/cpu-set-util.h | 47 ++++++---
src/core/dbus-execute.c | 35 ++-----
src/core/execute.c | 12 +--
src/core/execute.h | 4 +-
src/core/load-fragment.c | 31 +-----
src/core/main.c | 14 +--
src/nspawn/nspawn-settings.c | 33 +------
src/nspawn/nspawn-settings.h | 4 +-
src/nspawn/nspawn.c | 29 +++---
src/shared/bus-unit-util.c | 4 +-
src/test/test-cpu-set-util.c | 179 +++++++++++++++++++----------------
src/test/test-sizeof.c | 3 +
13 files changed, 286 insertions(+), 242 deletions(-)
diff --git a/src/basic/cpu-set-util.c b/src/basic/cpu-set-util.c
index 8f24a2601a..fe440f6381 100644
--- a/src/basic/cpu-set-util.c
+++ b/src/basic/cpu-set-util.c
@@ -15,14 +15,15 @@
#include "macro.h"
#include "parse-util.h"
#include "string-util.h"
+#include "util.h"
-char* cpu_set_to_string(const cpu_set_t *set, size_t setsize) {
+char* cpu_set_to_string(const CPUSet *a) {
_cleanup_free_ char *str = NULL;
size_t allocated = 0, len = 0;
int i, r;
- for (i = 0; (size_t) i < setsize * 8; i++) {
- if (!CPU_ISSET_S(i, setsize, set))
+ for (i = 0; (size_t) i < a->allocated * 8; i++) {
+ if (!CPU_ISSET_S(i, a->allocated, a->set))
continue;
if (!GREEDY_REALLOC(str, allocated, len + 1 + DECIMAL_STR_MAX(int)))
@@ -65,24 +66,74 @@ cpu_set_t* cpu_set_malloc(unsigned *ncpus) {
}
}
-int parse_cpu_set_internal(
+static int cpu_set_realloc(CPUSet *cpu_set, unsigned ncpus) {
+ size_t need;
+
+ assert(cpu_set);
+
+ need = CPU_ALLOC_SIZE(ncpus);
+ if (need > cpu_set->allocated) {
+ cpu_set_t *t;
+
+ t = realloc(cpu_set->set, need);
+ if (!t)
+ return -ENOMEM;
+
+ memzero((uint8_t*) t + cpu_set->allocated, need - cpu_set->allocated);
+
+ cpu_set->set = t;
+ cpu_set->allocated = need;
+ }
+
+ return 0;
+}
+
+static int cpu_set_add(CPUSet *cpu_set, unsigned cpu) {
+ int r;
+
+ if (cpu >= 8192)
+ /* As of kernel 5.1, CONFIG_NR_CPUS can be set to 8192 on PowerPC */
+ return -ERANGE;
+
+ r = cpu_set_realloc(cpu_set, cpu + 1);
+ if (r < 0)
+ return r;
+
+ CPU_SET_S(cpu, cpu_set->allocated, cpu_set->set);
+ return 0;
+}
+
+int cpu_set_add_all(CPUSet *a, const CPUSet *b) {
+ int r;
+
+ /* Do this backwards, so if we fail, we fail before changing anything. */
+ for (unsigned cpu_p1 = b->allocated * 8; cpu_p1 > 0; cpu_p1--)
+ if (CPU_ISSET_S(cpu_p1 - 1, b->allocated, b->set)) {
+ r = cpu_set_add(a, cpu_p1 - 1);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+
+int parse_cpu_set_full(
const char *rvalue,
- cpu_set_t **cpu_set,
+ CPUSet *cpu_set,
bool warn,
const char *unit,
const char *filename,
unsigned line,
const char *lvalue) {
- _cleanup_cpu_free_ cpu_set_t *c = NULL;
+ _cleanup_(cpu_set_reset) CPUSet c = {};
const char *p = rvalue;
- unsigned ncpus = 0;
- assert(rvalue);
+ assert(p);
for (;;) {
_cleanup_free_ char *word = NULL;
- unsigned cpu, cpu_lower, cpu_upper;
+ unsigned cpu_lower, cpu_upper;
int r;
r = extract_first_word(&p, &word, WHITESPACE ",", EXTRACT_QUOTES);
@@ -93,31 +144,63 @@ int parse_cpu_set_internal(
if (r == 0)
break;
- if (!c) {
- c = cpu_set_malloc(&ncpus);
- if (!c)
- return warn ? log_oom() : -ENOMEM;
- }
-
r = parse_range(word, &cpu_lower, &cpu_upper);
if (r < 0)
return warn ? log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse CPU affinity '%s'", word) : r;
- if (cpu_lower >= ncpus || cpu_upper >= ncpus)
- return warn ? log_syntax(unit, LOG_ERR, filename, line, EINVAL, "CPU out of range '%s' ncpus is %u", word, ncpus) : -EINVAL;
if (cpu_lower > cpu_upper) {
if (warn)
- log_syntax(unit, LOG_WARNING, filename, line, 0, "Range '%s' is invalid, %u > %u, ignoring", word, cpu_lower, cpu_upper);
- continue;
+ log_syntax(unit, LOG_WARNING, filename, line, 0, "Range '%s' is invalid, %u > %u, ignoring.",
+ word, cpu_lower, cpu_upper);
+
+ /* Make sure something is allocated, to distinguish this from the empty case */
+ r = cpu_set_realloc(&c, 1);
+ if (r < 0)
+ return r;
}
- for (cpu = cpu_lower; cpu <= cpu_upper; cpu++)
- CPU_SET_S(cpu, CPU_ALLOC_SIZE(ncpus), c);
+ for (unsigned cpu_p1 = MIN(cpu_upper, UINT_MAX-1) + 1; cpu_p1 > cpu_lower; cpu_p1--) {
+ r = cpu_set_add(&c, cpu_p1 - 1);
+ if (r < 0)
+ return warn ? log_syntax(unit, LOG_ERR, filename, line, r,
+ "Cannot add CPU %u to set: %m", cpu_p1 - 1) : r;
+ }
}
- /* On success, sets *cpu_set and returns ncpus for the system. */
- if (c)
- *cpu_set = TAKE_PTR(c);
+ /* On success, transfer ownership to the output variable */
+ *cpu_set = c;
+ c = (CPUSet) {};
+
+ return 0;
+}
+
+int parse_cpu_set_extend(
+ const char *rvalue,
+ CPUSet *old,
+ bool warn,
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *lvalue) {
+
+ _cleanup_(cpu_set_reset) CPUSet cpuset = {};
+ int r;
+
+ r = parse_cpu_set_full(rvalue, &cpuset, true, unit, filename, line, lvalue);
+ if (r < 0)
+ return r;
+
+ if (!cpuset.set) {
+ /* An empty assignment resets the CPU list */
+ cpu_set_reset(old);
+ return 0;
+ }
+
+ if (!old->set) {
+ *old = cpuset;
+ cpuset = (CPUSet) {};
+ return 0;
+ }
- return (int) ncpus;
+ return cpu_set_add_all(old, &cpuset);
}
diff --git a/src/basic/cpu-set-util.h b/src/basic/cpu-set-util.h
index 20612a8876..eb31b362fe 100644
--- a/src/basic/cpu-set-util.h
+++ b/src/basic/cpu-set-util.h
@@ -12,23 +12,40 @@
DEFINE_TRIVIAL_CLEANUP_FUNC(cpu_set_t*, CPU_FREE);
#define _cleanup_cpu_free_ _cleanup_(CPU_FREEp)
-static inline cpu_set_t* cpu_set_mfree(cpu_set_t *p) {
- if (p)
- CPU_FREE(p);
- return NULL;
-}
-
cpu_set_t* cpu_set_malloc(unsigned *ncpus);
-char* cpu_set_to_string(const cpu_set_t *set, size_t setsize);
-int parse_cpu_set_internal(const char *rvalue, cpu_set_t **cpu_set, bool warn, const char *unit, const char *filename, unsigned line, const char *lvalue);
-
-static inline int parse_cpu_set_and_warn(const char *rvalue, cpu_set_t **cpu_set, const char *unit, const char *filename, unsigned line, const char *lvalue) {
- assert(lvalue);
-
- return parse_cpu_set_internal(rvalue, cpu_set, true, unit, filename, line, lvalue);
+/* This wraps the libc interface with a variable to keep the allocated size. */
+typedef struct CPUSet {
+ cpu_set_t *set;
+ size_t allocated; /* in bytes */
+} CPUSet;
+
+static inline void cpu_set_reset(CPUSet *a) {
+ assert((a->allocated > 0) == !!a->set);
+ if (a->set)
+ CPU_FREE(a->set);
+ *a = (CPUSet) {};
}
-static inline int parse_cpu_set(const char *rvalue, cpu_set_t **cpu_set){
- return parse_cpu_set_internal(rvalue, cpu_set, false, NULL, NULL, 0, NULL);
+int cpu_set_add_all(CPUSet *a, const CPUSet *b);
+
+char* cpu_set_to_string(const CPUSet *a);
+int parse_cpu_set_full(
+ const char *rvalue,
+ CPUSet *cpu_set,
+ bool warn,
+ const char *unit,
+ const char *filename, unsigned line,
+ const char *lvalue);
+int parse_cpu_set_extend(
+ const char *rvalue,
+ CPUSet *old,
+ bool warn,
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *lvalue);
+
+static inline int parse_cpu_set(const char *rvalue, CPUSet *cpu_set){
+ return parse_cpu_set_full(rvalue, cpu_set, false, NULL, NULL, 0, NULL);
}
diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
index d9f4445745..08946627e3 100644
--- a/src/core/dbus-execute.c
+++ b/src/core/dbus-execute.c
@@ -220,7 +220,7 @@ static int property_get_cpu_affinity(
assert(reply);
assert(c);
- return sd_bus_message_append_array(reply, 'y', c->cpuset, CPU_ALLOC_SIZE(c->cpuset_ncpus));
+ return sd_bus_message_append_array(reply, 'y', c->cpu_set.set, c->cpu_set.allocated);
}
static int property_get_timer_slack_nsec(
@@ -1560,37 +1560,22 @@ int bus_exec_context_set_transient_property(
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
if (n == 0) {
- c->cpuset = cpu_set_mfree(c->cpuset);
- c->cpuset_ncpus = 0;
+ cpu_set_reset(&c->cpu_set);
unit_write_settingf(u, flags, name, "%s=", name);
} else {
_cleanup_free_ char *str = NULL;
- size_t ncpus;
+ const CPUSet set = {(cpu_set_t*) a, n};
- str = cpu_set_to_string(a, n);
+ str = cpu_set_to_string(&set);
if (!str)
return -ENOMEM;
- ncpus = CPU_SIZE_TO_NUM(n);
-
- if (!c->cpuset || c->cpuset_ncpus < ncpus) {
- cpu_set_t *cpuset;
-
- cpuset = CPU_ALLOC(ncpus);
- if (!cpuset)
- return -ENOMEM;
-
- CPU_ZERO_S(n, cpuset);
- if (c->cpuset) {
- CPU_OR_S(CPU_ALLOC_SIZE(c->cpuset_ncpus), cpuset, c->cpuset, (cpu_set_t*) a);
- CPU_FREE(c->cpuset);
- } else
- CPU_OR_S(n, cpuset, cpuset, (cpu_set_t*) a);
-
- c->cpuset = cpuset;
- c->cpuset_ncpus = ncpus;
- } else
- CPU_OR_S(n, c->cpuset, c->cpuset, (cpu_set_t*) a);
+ /* We forego any optimizations here, and always create the structure using
+ * cpu_set_add_all(), because we don't want to care if the existing size we
+ * got over dbus is appropriate. */
+ r = cpu_set_add_all(&c->cpu_set, &set);
+ if (r < 0)
+ return r;
unit_write_settingf(u, flags, name, "%s=%s", name, str);
}
diff --git a/src/core/execute.c b/src/core/execute.c
index c42300a41e..22e5825905 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -2991,8 +2991,8 @@ static int exec_child(
}
}
- if (context->cpuset)
- if (sched_setaffinity(0, CPU_ALLOC_SIZE(context->cpuset_ncpus), context->cpuset) < 0) {
+ if (context->cpu_set.set)
+ if (sched_setaffinity(0, context->cpu_set.allocated, context->cpu_set.set) < 0) {
*exit_status = EXIT_CPUAFFINITY;
return log_unit_error_errno(unit, errno, "Failed to set up CPU affinity: %m");
}
@@ -3694,7 +3694,7 @@ void exec_context_done(ExecContext *c) {
c->temporary_filesystems = NULL;
c->n_temporary_filesystems = 0;
- c->cpuset = cpu_set_mfree(c->cpuset);
+ cpu_set_reset(&c->cpu_set);
c->utmp_id = mfree(c->utmp_id);
c->selinux_context = mfree(c->selinux_context);
@@ -4097,10 +4097,10 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
prefix, yes_no(c->cpu_sched_reset_on_fork));
}
- if (c->cpuset) {
+ if (c->cpu_set.set) {
fprintf(f, "%sCPUAffinity:", prefix);
- for (i = 0; i < c->cpuset_ncpus; i++)
- if (CPU_ISSET_S(i, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset))
+ for (i = 0; i < c->cpu_set.allocated * 8; i++)
+ if (CPU_ISSET_S(i, c->cpu_set.allocated, c->cpu_set.set))
fprintf(f, " %u", i);
fputs("\n", f);
}
diff --git a/src/core/execute.h b/src/core/execute.h
index 8c91636adc..e1e7a494cd 100644
--- a/src/core/execute.h
+++ b/src/core/execute.h
@@ -14,6 +14,7 @@ typedef struct Manager Manager;
#include <sys/capability.h>
#include "cgroup-util.h"
+#include "cpu-set-util.h"
#include "fdset.h"
#include "list.h"
#include "missing.h"
@@ -148,8 +149,7 @@ struct ExecContext {
int cpu_sched_policy;
int cpu_sched_priority;
- cpu_set_t *cpuset;
- unsigned cpuset_ncpus;
+ CPUSet cpu_set;
ExecInput std_input;
ExecOutput std_output;
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index d9a5094aa0..34ae834188 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -1211,42 +1211,13 @@ int config_parse_exec_cpu_affinity(const char *unit,
void *userdata) {
ExecContext *c = data;
- _cleanup_cpu_free_ cpu_set_t *cpuset = NULL;
- int ncpus;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
- ncpus = parse_cpu_set_and_warn(rvalue, &cpuset, unit, filename, line, lvalue);
- if (ncpus < 0)
- return ncpus;
-
- if (ncpus == 0) {
- /* An empty assignment resets the CPU list */
- c->cpuset = cpu_set_mfree(c->cpuset);
- c->cpuset_ncpus = 0;
- return 0;
- }
-
- if (!c->cpuset) {
- c->cpuset = TAKE_PTR(cpuset);
- c->cpuset_ncpus = (unsigned) ncpus;
- return 0;
- }
-
- if (c->cpuset_ncpus < (unsigned) ncpus) {
- CPU_OR_S(CPU_ALLOC_SIZE(c->cpuset_ncpus), cpuset, c->cpuset, cpuset);
- CPU_FREE(c->cpuset);
- c->cpuset = TAKE_PTR(cpuset);
- c->cpuset_ncpus = (unsigned) ncpus;
- return 0;
- }
-
- CPU_OR_S(CPU_ALLOC_SIZE((unsigned) ncpus), c->cpuset, c->cpuset, cpuset);
-
- return 0;
+ return parse_cpu_set_extend(rvalue, &c->cpu_set, true, unit, filename, line, lvalue);
}
int config_parse_capability_set(
diff --git a/src/core/main.c b/src/core/main.c
index af7b26d6f1..e62b2756ee 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -537,16 +537,18 @@ static int config_parse_cpu_affinity2(
void *data,
void *userdata) {
- _cleanup_cpu_free_ cpu_set_t *c = NULL;
- int ncpus;
+ _cleanup_(cpu_set_reset) CPUSet c = {};
+ int r;
- ncpus = parse_cpu_set_and_warn(rvalue, &c, unit, filename, line, lvalue);
- if (ncpus < 0)
- return ncpus;
+ r = parse_cpu_set_full(rvalue, &c, true, unit, filename, line, lvalue);
+ if (r < 0)
+ return r;
- if (sched_setaffinity(0, CPU_ALLOC_SIZE(ncpus), c) < 0)
+ if (sched_setaffinity(0, c.allocated, c.set) < 0)
log_warning_errno(errno, "Failed to set CPU affinity: %m");
+ // FIXME: parsing and execution should be seperated.
+
return 0;
}
diff --git a/src/nspawn/nspawn-settings.c b/src/nspawn/nspawn-settings.c
index 62a3486952..21c24a1111 100644
--- a/src/nspawn/nspawn-settings.c
+++ b/src/nspawn/nspawn-settings.c
@@ -85,7 +85,7 @@ Settings* settings_free(Settings *s) {
strv_free(s->syscall_blacklist);
rlimit_free_all(s->rlimit);
free(s->hostname);
- s->cpuset = cpu_set_mfree(s->cpuset);
+ cpu_set_reset(&s->cpu_set);
strv_free(s->network_interfaces);
strv_free(s->network_macvlan);
@@ -687,41 +687,12 @@ int config_parse_cpu_affinity(
void *data,
void *userdata) {
- _cleanup_cpu_free_ cpu_set_t *cpuset = NULL;
Settings *settings = data;
- int ncpus;
assert(rvalue);
assert(settings);
- ncpus = parse_cpu_set_and_warn(rvalue, &cpuset, unit, filename, line, lvalue);
- if (ncpus < 0)
- return ncpus;
-
- if (ncpus == 0) {
- /* An empty assignment resets the CPU list */
- settings->cpuset = cpu_set_mfree(settings->cpuset);
- settings->cpuset_ncpus = 0;
- return 0;
- }
-
- if (!settings->cpuset) {
- settings->cpuset = TAKE_PTR(cpuset);
- settings->cpuset_ncpus = (unsigned) ncpus;
- return 0;
- }
-
- if (settings->cpuset_ncpus < (unsigned) ncpus) {
- CPU_OR_S(CPU_ALLOC_SIZE(settings->cpuset_ncpus), cpuset, settings->cpuset, cpuset);
- CPU_FREE(settings->cpuset);
- settings->cpuset = TAKE_PTR(cpuset);
- settings->cpuset_ncpus = (unsigned) ncpus;
- return 0;
- }
-
- CPU_OR_S(CPU_ALLOC_SIZE((unsigned) ncpus), settings->cpuset, settings->cpuset, cpuset);
-
- return 0;
+ return parse_cpu_set_extend(rvalue, &settings->cpu_set, true, unit, filename, line, lvalue);
}
DEFINE_CONFIG_PARSE_ENUM(config_parse_resolv_conf, resolv_conf_mode, ResolvConfMode, "Failed to parse resolv.conf mode");
diff --git a/src/nspawn/nspawn-settings.h b/src/nspawn/nspawn-settings.h
index d522f3cb36..da863ef11c 100644
--- a/src/nspawn/nspawn-settings.h
+++ b/src/nspawn/nspawn-settings.h
@@ -7,6 +7,7 @@
#include "sd-id128.h"
#include "conf-parser.h"
+#include "cpu-set-util.h"
#include "macro.h"
#include "nspawn-expose-ports.h"
#include "nspawn-mount.h"
@@ -123,8 +124,7 @@ typedef struct Settings {
int no_new_privileges;
int oom_score_adjust;
bool oom_score_adjust_set;
- cpu_set_t *cpuset;
- unsigned cpuset_ncpus;
+ CPUSet cpu_set;
ResolvConfMode resolv_conf;
LinkJournal link_journal;
bool link_journal_try;
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index b40411dcd0..08255b5724 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -199,8 +199,7 @@ static struct rlimit *arg_rlimit[_RLIMIT_MAX] = {};
static bool arg_no_new_privileges = false;
static int arg_oom_score_adjust = 0;
static bool arg_oom_score_adjust_set = false;
-static cpu_set_t *arg_cpuset = NULL;
-static unsigned arg_cpuset_ncpus = 0;
+static CPUSet arg_cpu_set = {};
static ResolvConfMode arg_resolv_conf = RESOLV_CONF_AUTO;
static TimezoneMode arg_timezone = TIMEZONE_AUTO;
@@ -1186,17 +1185,14 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_CPU_AFFINITY: {
- _cleanup_cpu_free_ cpu_set_t *cpuset = NULL;
+ CPUSet cpuset;
r = parse_cpu_set(optarg, &cpuset);
if (r < 0)
- return log_error_errno(r, "Failed to parse CPU affinity mask: %s", optarg);
+ return log_error_errno(r, "Failed to parse CPU affinity mask %s: %m", optarg);
- if (arg_cpuset)
- CPU_FREE(arg_cpuset);
-
- arg_cpuset = TAKE_PTR(cpuset);
- arg_cpuset_ncpus = r;
+ cpu_set_reset(&arg_cpu_set);
+ arg_cpu_set = cpuset;
arg_settings_mask |= SETTING_CPU_AFFINITY;
break;
}
@@ -2631,8 +2627,8 @@ static int inner_child(
return log_error_errno(r, "Failed to adjust OOM score: %m");
}
- if (arg_cpuset)
- if (sched_setaffinity(0, CPU_ALLOC_SIZE(arg_cpuset_ncpus), arg_cpuset) < 0)
+ if (arg_cpu_set.set)
+ if (sched_setaffinity(0, arg_cpu_set.allocated, arg_cpu_set.set) < 0)
return log_error_errno(errno, "Failed to set CPU affinity: %m");
r = drop_capabilities();
@@ -3494,15 +3490,14 @@ static int merge_settings(Settings *settings, const char *path) {
}
if ((arg_settings_mask & SETTING_CPU_AFFINITY) == 0 &&
- settings->cpuset) {
+ settings->cpu_set.set) {
if (!arg_settings_trusted)
log_warning("Ignoring CPUAffinity= setting, file '%s' is not trusted.", path);
else {
- if (arg_cpuset)
- CPU_FREE(arg_cpuset);
- arg_cpuset = TAKE_PTR(settings->cpuset);
- arg_cpuset_ncpus = settings->cpuset_ncpus;
+ cpu_set_reset(&arg_cpu_set);
+ arg_cpu_set = settings->cpu_set;
+ settings->cpu_set = (CPUSet) {};
}
}
@@ -4600,7 +4595,7 @@ finish:
rlimit_free_all(arg_rlimit);
strv_free(arg_syscall_whitelist);
strv_free(arg_syscall_blacklist);
- arg_cpuset = cpu_set_mfree(arg_cpuset);
+ cpu_set_reset(&arg_cpu_set);
return r < 0 ? EXIT_FAILURE : ret;
}
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
index 271cc054da..75b4aace84 100644
--- a/src/shared/bus-unit-util.c
+++ b/src/shared/bus-unit-util.c
@@ -932,13 +932,13 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
}
if (streq(field, "CPUAffinity")) {
- _cleanup_cpu_free_ cpu_set_t *cpuset = NULL;
+ _cleanup_(cpu_set_reset) CPUSet cpuset = {};
r = parse_cpu_set(eq, &cpuset);
if (r < 0)
return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
- return bus_append_byte_array(m, field, cpuset, CPU_ALLOC_SIZE(r));
+ return bus_append_byte_array(m, field, cpuset.set, cpuset.allocated);
}
if (STR_IN_SET(field, "RestrictAddressFamilies", "SystemCallFilter")) {
diff --git a/src/test/test-cpu-set-util.c b/src/test/test-cpu-set-util.c
index ff5edb2a69..b9ec29af66 100644
--- a/src/test/test-cpu-set-util.c
+++ b/src/test/test-cpu-set-util.c
@@ -1,154 +1,171 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
+#include <errno.h>
+
#include "alloc-util.h"
#include "cpu-set-util.h"
#include "macro.h"
static void test_parse_cpu_set(void) {
- cpu_set_t *c = NULL;
+ CPUSet c = {};
_cleanup_free_ char *str = NULL;
- int ncpus;
int cpu;
/* Simple range (from CPUAffinity example) */
- ncpus = parse_cpu_set_and_warn("1 2", &c, NULL, "fake", 1, "CPUAffinity");
- assert_se(ncpus >= 1024);
- assert_se(CPU_ISSET_S(1, CPU_ALLOC_SIZE(ncpus), c));
- assert_se(CPU_ISSET_S(2, CPU_ALLOC_SIZE(ncpus), c));
- assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 2);
-
- assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus)));
+ assert_se(parse_cpu_set_full("1 2", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
+ assert_se(c.set);
+ assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
+ assert_se(CPU_ISSET_S(1, c.allocated, c.set));
+ assert_se(CPU_ISSET_S(2, c.allocated, c.set));
+ assert_se(CPU_COUNT_S(c.allocated, c.set) == 2);
+
+ assert_se(str = cpu_set_to_string(&c));
log_info("cpu_set_to_string: %s", str);
str = mfree(str);
- c = cpu_set_mfree(c);
+ cpu_set_reset(&c);
/* A more interesting range */
- ncpus = parse_cpu_set_and_warn("0 1 2 3 8 9 10 11", &c, NULL, "fake", 1, "CPUAffinity");
- assert_se(ncpus >= 1024);
- assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8);
+ assert_se(parse_cpu_set_full("0 1 2 3 8 9 10 11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
+ assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
+ assert_se(CPU_COUNT_S(c.allocated, c.set) == 8);
for (cpu = 0; cpu < 4; cpu++)
- assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
+ assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
for (cpu = 8; cpu < 12; cpu++)
- assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
- assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus)));
+ assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
+ assert_se(str = cpu_set_to_string(&c));
log_info("cpu_set_to_string: %s", str);
str = mfree(str);
- c = cpu_set_mfree(c);
+ cpu_set_reset(&c);
/* Quoted strings */
- ncpus = parse_cpu_set_and_warn("8 '9' 10 \"11\"", &c, NULL, "fake", 1, "CPUAffinity");
- assert_se(ncpus >= 1024);
- assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 4);
+ assert_se(parse_cpu_set_full("8 '9' 10 \"11\"", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
+ assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
+ assert_se(CPU_COUNT_S(c.allocated, c.set) == 4);
for (cpu = 8; cpu < 12; cpu++)
- assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
- assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus)));
+ assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
+ assert_se(str = cpu_set_to_string(&c));
log_info("cpu_set_to_string: %s", str);
str = mfree(str);
- c = cpu_set_mfree(c);
+ cpu_set_reset(&c);
/* Use commas as separators */
- ncpus = parse_cpu_set_and_warn("0,1,2,3 8,9,10,11", &c, NULL, "fake", 1, "CPUAffinity");
- assert_se(ncpus >= 1024);
- assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8);
+ assert_se(parse_cpu_set_full("0,1,2,3 8,9,10,11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
+ assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
+ assert_se(CPU_COUNT_S(c.allocated, c.set) == 8);
for (cpu = 0; cpu < 4; cpu++)
- assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
+ assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
for (cpu = 8; cpu < 12; cpu++)
- assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
- assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus)));
+ assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
+ assert_se(str = cpu_set_to_string(&c));
log_info("cpu_set_to_string: %s", str);
str = mfree(str);
- c = cpu_set_mfree(c);
+ cpu_set_reset(&c);
/* Commas with spaces (and trailing comma, space) */
- ncpus = parse_cpu_set_and_warn("0, 1, 2, 3, 4, 5, 6, 7, ", &c, NULL, "fake", 1, "CPUAffinity");
- assert_se(ncpus >= 1024);
- assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8);
+ assert_se(parse_cpu_set_full("0, 1, 2, 3, 4, 5, 6, 7, ", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
+ assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
+ assert_se(CPU_COUNT_S(c.allocated, c.set) == 8);
for (cpu = 0; cpu < 8; cpu++)
- assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
- assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus)));
+ assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
+ assert_se(str = cpu_set_to_string(&c));
log_info("cpu_set_to_string: %s", str);
str = mfree(str);
- c = cpu_set_mfree(c);
+ cpu_set_reset(&c);
/* Ranges */
- ncpus = parse_cpu_set_and_warn("0-3,8-11", &c, NULL, "fake", 1, "CPUAffinity");
- assert_se(ncpus >= 1024);
- assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8);
+ assert_se(parse_cpu_set_full("0-3,8-11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
+ assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
+ assert_se(CPU_COUNT_S(c.allocated, c.set) == 8);
for (cpu = 0; cpu < 4; cpu++)
- assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
+ assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
for (cpu = 8; cpu < 12; cpu++)
- assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
- assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus)));
+ assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
+ assert_se(str = cpu_set_to_string(&c));
log_info("cpu_set_to_string: %s", str);
str = mfree(str);
- c = cpu_set_mfree(c);
+ cpu_set_reset(&c);
/* Ranges with trailing comma, space */
- ncpus = parse_cpu_set_and_warn("0-3 8-11, ", &c, NULL, "fake", 1, "CPUAffinity");
- assert_se(ncpus >= 1024);
- assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8);
+ assert_se(parse_cpu_set_full("0-3 8-11, ", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
+ assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
+ assert_se(CPU_COUNT_S(c.allocated, c.set) == 8);
for (cpu = 0; cpu < 4; cpu++)
- assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
+ assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
for (cpu = 8; cpu < 12; cpu++)
- assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
- assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus)));
+ assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
+ assert_se(str = cpu_set_to_string(&c));
log_info("cpu_set_to_string: %s", str);
str = mfree(str);
- c = cpu_set_mfree(c);
+ cpu_set_reset(&c);
/* Negative range (returns empty cpu_set) */
- ncpus = parse_cpu_set_and_warn("3-0", &c, NULL, "fake", 1, "CPUAffinity");
- assert_se(ncpus >= 1024);
- assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 0);
- c = cpu_set_mfree(c);
+ assert_se(parse_cpu_set_full("3-0", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
+ assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
+ assert_se(CPU_COUNT_S(c.allocated, c.set) == 0);
+ cpu_set_reset(&c);
/* Overlapping ranges */
- ncpus = parse_cpu_set_and_warn("0-7 4-11", &c, NULL, "fake", 1, "CPUAffinity");
- assert_se(ncpus >= 1024);
- assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 12);
+ assert_se(parse_cpu_set_full("0-7 4-11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
+ assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
+ assert_se(CPU_COUNT_S(c.allocated, c.set) == 12);
for (cpu = 0; cpu < 12; cpu++)
- assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
- assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus)));
+ assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
+ assert_se(str = cpu_set_to_string(&c));
log_info("cpu_set_to_string: %s", str);
str = mfree(str);
- c = cpu_set_mfree(c);
+ cpu_set_reset(&c);
/* Mix ranges and individual CPUs */
- ncpus = parse_cpu_set_and_warn("0,1 4-11", &c, NULL, "fake", 1, "CPUAffinity");
- assert_se(ncpus >= 1024);
- assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 10);
- assert_se(CPU_ISSET_S(0, CPU_ALLOC_SIZE(ncpus), c));
- assert_se(CPU_ISSET_S(1, CPU_ALLOC_SIZE(ncpus), c));
+ assert_se(parse_cpu_set_full("0,1 4-11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
+ assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
+ assert_se(CPU_COUNT_S(c.allocated, c.set) == 10);
+ assert_se(CPU_ISSET_S(0, c.allocated, c.set));
+ assert_se(CPU_ISSET_S(1, c.allocated, c.set));
for (cpu = 4; cpu < 12; cpu++)
- assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
- assert_se(str = cpu_set_to_string(c, CPU_ALLOC_SIZE(ncpus)));
+ assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
+ assert_se(str = cpu_set_to_string(&c));
log_info("cpu_set_to_string: %s", str);
str = mfree(str);
- c = cpu_set_mfree(c);
+ cpu_set_reset(&c);
/* Garbage */
- ncpus = parse_cpu_set_and_warn("0 1 2 3 garbage", &c, NULL, "fake", 1, "CPUAffinity");
- assert_se(ncpus < 0);
- assert_se(!c);
+ assert_se(parse_cpu_set_full("0 1 2 3 garbage", &c, true, NULL, "fake", 1, "CPUAffinity") == -EINVAL);
+ assert_se(!c.set);
+ assert_se(c.allocated == 0);
/* Range with garbage */
- ncpus = parse_cpu_set_and_warn("0-3 8-garbage", &c, NULL, "fake", 1, "CPUAffinity");
- assert_se(ncpus < 0);
- assert_se(!c);
+ assert_se(parse_cpu_set_full("0-3 8-garbage", &c, true, NULL, "fake", 1, "CPUAffinity") == -EINVAL);
+ assert_se(!c.set);
+ assert_se(c.allocated == 0);
/* Empty string */
- c = NULL;
- ncpus = parse_cpu_set_and_warn("", &c, NULL, "fake", 1, "CPUAffinity");
- assert_se(ncpus == 0); /* empty string returns 0 */
- assert_se(!c);
+ assert_se(parse_cpu_set_full("", &c, true, NULL, "fake", 1, "CPUAffinity") == 0);
+ assert_se(!c.set); /* empty string returns NULL */
+ assert_se(c.allocated == 0);
/* Runaway quoted string */
- ncpus = parse_cpu_set_and_warn("0 1 2 3 \"4 5 6 7 ", &c, NULL, "fake", 1, "CPUAffinity");
- assert_se(ncpus < 0);
- assert_se(!c);
+ assert_se(parse_cpu_set_full("0 1 2 3 \"4 5 6 7 ", &c, true, NULL, "fake", 1, "CPUAffinity") == -EINVAL);
+ assert_se(!c.set);
+ assert_se(c.allocated == 0);
+
+ /* Maximum allocation */
+ assert_se(parse_cpu_set_full("8000-8191", &c, true, NULL, "fake", 1, "CPUAffinity") == 0);
+ assert_se(CPU_COUNT_S(c.allocated, c.set) == 192);
+ assert_se(str = cpu_set_to_string(&c));
+ log_info("cpu_set_to_string: %s", str);
+ str = mfree(str);
+ cpu_set_reset(&c);
}
int main(int argc, char *argv[]) {
+ log_info("CPU_ALLOC_SIZE(1) = %zu", CPU_ALLOC_SIZE(1));
+ log_info("CPU_ALLOC_SIZE(9) = %zu", CPU_ALLOC_SIZE(9));
+ log_info("CPU_ALLOC_SIZE(64) = %zu", CPU_ALLOC_SIZE(64));
+ log_info("CPU_ALLOC_SIZE(65) = %zu", CPU_ALLOC_SIZE(65));
+ log_info("CPU_ALLOC_SIZE(1024) = %zu", CPU_ALLOC_SIZE(1024));
+ log_info("CPU_ALLOC_SIZE(1025) = %zu", CPU_ALLOC_SIZE(1025));
+ log_info("CPU_ALLOC_SIZE(8191) = %zu", CPU_ALLOC_SIZE(8191));
+
test_parse_cpu_set();
return 0;
diff --git a/src/test/test-sizeof.c b/src/test/test-sizeof.c
index 7a1e496ed2..396e68f35f 100644
--- a/src/test/test-sizeof.c
+++ b/src/test/test-sizeof.c
@@ -1,5 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
+#include <sched.h>
#include <stdio.h>
#include <string.h>
@@ -64,6 +65,8 @@ int main(void) {
info(uid_t);
info(gid_t);
+ info(__cpu_mask);
+
info(enum Enum);
info(enum BigEnum);
info(enum BigEnum2);

View File

@ -0,0 +1,125 @@
From 42032749e61076b3d9e5004432073c2a5ea737ce Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Tue, 28 May 2019 21:28:31 +0200
Subject: [PATCH] Move cpus_in_affinity_mask() to cpu-set-util.[ch]
It just seems to fit better there and it's always better to have things
in shared/ rather than basic/.
(cherry picked from commit f44b3035d4a698aa0ce08a552199b54d43de3d85)
Related: #1734787
---
src/basic/cpu-set-util.c | 34 ++++++++++++++++++++++++++++++++++
src/basic/cpu-set-util.h | 2 ++
src/basic/process-util.c | 5 ++---
src/shared/condition.c | 1 +
src/test/test-condition.c | 1 +
5 files changed, 40 insertions(+), 3 deletions(-)
diff --git a/src/basic/cpu-set-util.c b/src/basic/cpu-set-util.c
index fe440f6381..1803539ac6 100644
--- a/src/basic/cpu-set-util.c
+++ b/src/basic/cpu-set-util.c
@@ -204,3 +204,37 @@ int parse_cpu_set_extend(
return cpu_set_add_all(old, &cpuset);
}
+
+int cpus_in_affinity_mask(void) {
+ size_t n = 16;
+ int r;
+
+ for (;;) {
+ cpu_set_t *c;
+
+ c = CPU_ALLOC(n);
+ if (!c)
+ return -ENOMEM;
+
+ if (sched_getaffinity(0, CPU_ALLOC_SIZE(n), c) >= 0) {
+ int k;
+
+ k = CPU_COUNT_S(CPU_ALLOC_SIZE(n), c);
+ CPU_FREE(c);
+
+ if (k <= 0)
+ return -EINVAL;
+
+ return k;
+ }
+
+ r = -errno;
+ CPU_FREE(c);
+
+ if (r != -EINVAL)
+ return r;
+ if (n > SIZE_MAX/2)
+ return -ENOMEM;
+ n *= 2;
+ }
+}
diff --git a/src/basic/cpu-set-util.h b/src/basic/cpu-set-util.h
index eb31b362fe..9b026aca09 100644
--- a/src/basic/cpu-set-util.h
+++ b/src/basic/cpu-set-util.h
@@ -49,3 +49,5 @@ int parse_cpu_set_extend(
static inline int parse_cpu_set(const char *rvalue, CPUSet *cpu_set){
return parse_cpu_set_full(rvalue, cpu_set, false, NULL, NULL, 0, NULL);
}
+
+int cpus_in_affinity_mask(void);
diff --git a/src/basic/process-util.c b/src/basic/process-util.c
index 6dbeee9dda..0a4a747ba4 100644
--- a/src/basic/process-util.c
+++ b/src/basic/process-util.c
@@ -4,7 +4,6 @@
#include <errno.h>
#include <limits.h>
#include <linux/oom.h>
-#include <sched.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
@@ -1474,7 +1473,7 @@ static const char *const ioprio_class_table[] = {
[IOPRIO_CLASS_NONE] = "none",
[IOPRIO_CLASS_RT] = "realtime",
[IOPRIO_CLASS_BE] = "best-effort",
- [IOPRIO_CLASS_IDLE] = "idle"
+ [IOPRIO_CLASS_IDLE] = "idle",
};
DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ioprio_class, int, IOPRIO_N_CLASSES);
@@ -1495,7 +1494,7 @@ static const char* const sched_policy_table[] = {
[SCHED_BATCH] = "batch",
[SCHED_IDLE] = "idle",
[SCHED_FIFO] = "fifo",
- [SCHED_RR] = "rr"
+ [SCHED_RR] = "rr",
};
DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(sched_policy, int, INT_MAX);
diff --git a/src/shared/condition.c b/src/shared/condition.c
index 2969a89b4e..b829f0528c 100644
--- a/src/shared/condition.c
+++ b/src/shared/condition.c
@@ -21,6 +21,7 @@
#include "cap-list.h"
#include "cgroup-util.h"
#include "condition.h"
+#include "cpu-set-util.h"
#include "efivars.h"
#include "extract-word.h"
#include "fd-util.h"
diff --git a/src/test/test-condition.c b/src/test/test-condition.c
index 7ce6ee80ea..24395dafc6 100644
--- a/src/test/test-condition.c
+++ b/src/test/test-condition.c
@@ -13,6 +13,7 @@
#include "audit-util.h"
#include "cgroup-util.h"
#include "condition.h"
+#include "cpu-set-util.h"
#include "efivars.h"
#include "hostname-util.h"
#include "id128-util.h"

View File

@ -0,0 +1,40 @@
From a1ed6bfc5a8c40377b9f1cab1acc3c67a9529427 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Tue, 21 May 2019 09:01:34 +0200
Subject: [PATCH] test-cpu-set-util: add simple test for
cpus_in_affinity_mask()
(cherry picked from commit 9d1345f0657c707df89b41b2738776efb40aec8e)
Related: #1734787
---
src/test/test-cpu-set-util.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/src/test/test-cpu-set-util.c b/src/test/test-cpu-set-util.c
index b9ec29af66..e87e0ca6e6 100644
--- a/src/test/test-cpu-set-util.c
+++ b/src/test/test-cpu-set-util.c
@@ -157,6 +157,14 @@ static void test_parse_cpu_set(void) {
cpu_set_reset(&c);
}
+static void test_cpus_in_affinity_mask(void) {
+ int r;
+
+ r = cpus_in_affinity_mask();
+ assert(r > 0);
+ log_info("cpus_in_affinity_mask: %d", r);
+}
+
int main(int argc, char *argv[]) {
log_info("CPU_ALLOC_SIZE(1) = %zu", CPU_ALLOC_SIZE(1));
log_info("CPU_ALLOC_SIZE(9) = %zu", CPU_ALLOC_SIZE(9));
@@ -167,6 +175,7 @@ int main(int argc, char *argv[]) {
log_info("CPU_ALLOC_SIZE(8191) = %zu", CPU_ALLOC_SIZE(8191));
test_parse_cpu_set();
+ test_cpus_in_affinity_mask();
return 0;
}

View File

@ -0,0 +1,63 @@
From 69541e93c45efb7ee15d7584c3aa70c3ff0b2200 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Fri, 24 May 2019 08:50:41 +0200
Subject: [PATCH] test-cpu-set-util: add a smoke test for
test_parse_cpu_set_extend()
(cherry picked from commit b54d7241f25b859c6c008e516c2131c39902e6e4)
Related: #1734787
---
src/test/test-cpu-set-util.c | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/src/test/test-cpu-set-util.c b/src/test/test-cpu-set-util.c
index e87e0ca6e6..81f67647e8 100644
--- a/src/test/test-cpu-set-util.c
+++ b/src/test/test-cpu-set-util.c
@@ -11,6 +11,8 @@ static void test_parse_cpu_set(void) {
_cleanup_free_ char *str = NULL;
int cpu;
+ log_info("/* %s */", __func__);
+
/* Simple range (from CPUAffinity example) */
assert_se(parse_cpu_set_full("1 2", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
assert_se(c.set);
@@ -157,6 +159,28 @@ static void test_parse_cpu_set(void) {
cpu_set_reset(&c);
}
+static void test_parse_cpu_set_extend(void) {
+ CPUSet c = {};
+ _cleanup_free_ char *s1 = NULL, *s2 = NULL;
+
+ log_info("/* %s */", __func__);
+
+ assert_se(parse_cpu_set_extend("1 3", &c, true, NULL, "fake", 1, "CPUAffinity") == 0);
+ assert_se(CPU_COUNT_S(c.allocated, c.set) == 2);
+ assert_se(s1 = cpu_set_to_string(&c));
+ log_info("cpu_set_to_string: %s", s1);
+
+ assert_se(parse_cpu_set_extend("4", &c, true, NULL, "fake", 1, "CPUAffinity") == 0);
+ assert_se(CPU_COUNT_S(c.allocated, c.set) == 3);
+ assert_se(s2 = cpu_set_to_string(&c));
+ log_info("cpu_set_to_string: %s", s2);
+
+ assert_se(parse_cpu_set_extend("", &c, true, NULL, "fake", 1, "CPUAffinity") == 0);
+ assert_se(!c.set);
+ assert_se(c.allocated == 0);
+ log_info("cpu_set_to_string: (null)");
+}
+
static void test_cpus_in_affinity_mask(void) {
int r;
@@ -175,6 +199,7 @@ int main(int argc, char *argv[]) {
log_info("CPU_ALLOC_SIZE(8191) = %zu", CPU_ALLOC_SIZE(8191));
test_parse_cpu_set();
+ test_parse_cpu_set_extend();
test_cpus_in_affinity_mask();
return 0;

View File

@ -0,0 +1,148 @@
From 8bf8409c6e08f5aef35d1976e172b3f61b651c8d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Fri, 24 May 2019 08:35:51 +0200
Subject: [PATCH] pid1: parse CPUAffinity= in incremental fashion
This makes the handling of this option match what we do in unit files. I think
consistency is important here. (As it happens, it is the only option in
system.conf that is "non-atomic", i.e. where there's a list of things which can
be split over multiple assignments. All other options are single-valued, so
there's no issue of how to handle multiple assignments.)
(cherry picked from commit 61fbbac1d517a0b3498a689c736c6ca918497904)
Related: #1734787
---
man/systemd-system.conf.xml | 13 ++++++++-----
man/systemd.exec.xml | 2 +-
src/core/main.c | 36 ++++++++++++++++++++++++++----------
3 files changed, 35 insertions(+), 16 deletions(-)
diff --git a/man/systemd-system.conf.xml b/man/systemd-system.conf.xml
index 085086200a..ab23779ec0 100644
--- a/man/systemd-system.conf.xml
+++ b/man/systemd-system.conf.xml
@@ -99,11 +99,14 @@
<varlistentry>
<term><varname>CPUAffinity=</varname></term>
- <listitem><para>Configures the initial CPU affinity for the
- init process. Takes a list of CPU indices or ranges separated
- by either whitespace or commas. CPU ranges are specified by
- the lower and upper CPU indices separated by a
- dash.</para></listitem>
+ <listitem><para>Configures the CPU affinity for the service manager as well as the default CPU
+ affinity for all forked off processes. Takes a list of CPU indices or ranges separated by either
+ whitespace or commas. CPU ranges are specified by the lower and upper CPU indices separated by a
+ dash. This option may be specified more than once, in which case the specified CPU affinity masks are
+ merged. If the empty string is assigned, the mask is reset, all assignments prior to this will have
+ no effect. Individual services may override the CPU affinity for their processes with the
+ <varname>CPUAffinity=</varname> setting in unit files, see
+ <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para></listitem>
</varlistentry>
<varlistentry>
diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml
index 737c52bcc4..342b8385bc 100644
--- a/man/systemd.exec.xml
+++ b/man/systemd.exec.xml
@@ -703,7 +703,7 @@ CapabilityBoundingSet=~CAP_B CAP_C</programlisting>
<listitem><para>Controls the CPU affinity of the executed processes. Takes a list of CPU indices or ranges
separated by either whitespace or commas. CPU ranges are specified by the lower and upper CPU indices separated
- by a dash. This option may be specified more than once, in which case the specified CPU affinity masks are
+ by a dash. This option may be specified more than once, in which case the specified CPU affinity masks are
merged. If the empty string is assigned, the mask is reset, all assignments prior to this will have no
effect. See
<citerefentry><refentrytitle>sched_setaffinity</refentrytitle><manvolnum>2</manvolnum></citerefentry> for
diff --git a/src/core/main.c b/src/core/main.c
index e62b2756ee..bc1db2af7b 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -127,6 +127,7 @@ static bool arg_default_tasks_accounting = true;
static uint64_t arg_default_tasks_max = UINT64_MAX;
static sd_id128_t arg_machine_id = {};
static EmergencyAction arg_cad_burst_action = EMERGENCY_ACTION_REBOOT_FORCE;
+static CPUSet arg_cpu_affinity = {};
_noreturn_ static void freeze_or_reboot(void) {
@@ -537,17 +538,11 @@ static int config_parse_cpu_affinity2(
void *data,
void *userdata) {
- _cleanup_(cpu_set_reset) CPUSet c = {};
- int r;
-
- r = parse_cpu_set_full(rvalue, &c, true, unit, filename, line, lvalue);
- if (r < 0)
- return r;
+ CPUSet *affinity = data;
- if (sched_setaffinity(0, c.allocated, c.set) < 0)
- log_warning_errno(errno, "Failed to set CPU affinity: %m");
+ assert(affinity);
- // FIXME: parsing and execution should be seperated.
+ (void) parse_cpu_set_extend(rvalue, affinity, true, unit, filename, line, lvalue);
return 0;
}
@@ -655,7 +650,7 @@ static int parse_config_file(void) {
{ "Manager", "CrashShell", config_parse_bool, 0, &arg_crash_shell },
{ "Manager", "CrashReboot", config_parse_bool, 0, &arg_crash_reboot },
{ "Manager", "ShowStatus", config_parse_show_status, 0, &arg_show_status },
- { "Manager", "CPUAffinity", config_parse_cpu_affinity2, 0, NULL },
+ { "Manager", "CPUAffinity", config_parse_cpu_affinity2, 0, &arg_cpu_affinity },
{ "Manager", "JoinControllers", config_parse_join_controllers, 0, &arg_join_controllers },
{ "Manager", "RuntimeWatchdogSec", config_parse_sec, 0, &arg_runtime_watchdog },
{ "Manager", "ShutdownWatchdogSec", config_parse_sec, 0, &arg_shutdown_watchdog },
@@ -1483,6 +1478,21 @@ static void initialize_coredump(bool skip_setup) {
#endif
}
+static void update_cpu_affinity(bool skip_setup) {
+ _cleanup_free_ char *mask = NULL;
+
+ if (skip_setup || !arg_cpu_affinity.set)
+ return;
+
+ assert(arg_cpu_affinity.allocated > 0);
+
+ mask = cpu_set_to_string(&arg_cpu_affinity);
+ log_debug("Setting CPU affinity to %s.", strnull(mask));
+
+ if (sched_setaffinity(0, arg_cpu_affinity.allocated, arg_cpu_affinity.set) < 0)
+ log_warning_errno(errno, "Failed to set CPU affinity: %m");
+}
+
static void do_reexecute(
int argc,
char *argv[],
@@ -1655,6 +1665,8 @@ static int invoke_main_loop(
set_manager_defaults(m);
+ update_cpu_affinity(false);
+
if (saved_log_level >= 0)
manager_override_log_level(m, saved_log_level);
if (saved_log_target >= 0)
@@ -1813,6 +1825,8 @@ static int initialize_runtime(
if (arg_action != ACTION_RUN)
return 0;
+ update_cpu_affinity(skip_setup);
+
if (arg_system) {
/* Make sure we leave a core dump without panicing the kernel. */
install_crash_handler();
@@ -1947,6 +1961,8 @@ static void free_arguments(void) {
arg_join_controllers = strv_free_free(arg_join_controllers);
arg_default_environment = strv_free(arg_default_environment);
arg_syscall_archs = set_free(arg_syscall_archs);
+
+ cpu_set_reset(&arg_cpu_affinity);
}
static int load_configuration(int argc, char **argv, const char **ret_error_message) {

View File

@ -0,0 +1,86 @@
From f71f3271fa149d2b5f022830d43071d97b022b38 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Fri, 24 May 2019 08:59:23 +0200
Subject: [PATCH] pid1: don't reset setting from /proc/cmdline upon restart
We have settings which may be set on the kernel command line, and also
in /proc/cmdline (for pid1). The settings in /proc/cmdline have higher priority
of course. When a reload was done, we'd reload just the configuration file,
losing the overrides.
So read /proc/cmdline again during reload.
Also, when initially reading the configuration file when program starts,
don't treat any errors as fatal. The configuration done in there doesn't
seem important enough to refuse boot.
(cherry picked from commit 470a5e6dcec4637439ae953002127af214d396ac)
Related: #1734787
---
src/core/main.c | 26 ++++++++++++++++----------
1 file changed, 16 insertions(+), 10 deletions(-)
diff --git a/src/core/main.c b/src/core/main.c
index bc1db2af7b..9a9f145080 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -129,6 +129,8 @@ static sd_id128_t arg_machine_id = {};
static EmergencyAction arg_cad_burst_action = EMERGENCY_ACTION_REBOOT_FORCE;
static CPUSet arg_cpu_affinity = {};
+static int parse_configuration(void);
+
_noreturn_ static void freeze_or_reboot(void) {
if (arg_crash_reboot) {
@@ -1659,9 +1661,7 @@ static int invoke_main_loop(
saved_log_level = m->log_level_overridden ? log_get_max_level() : -1;
saved_log_target = m->log_target_overridden ? log_get_target() : _LOG_TARGET_INVALID;
- r = parse_config_file();
- if (r < 0)
- log_warning_errno(r, "Failed to parse config file, ignoring: %m");
+ (void) parse_configuration();
set_manager_defaults(m);
@@ -1965,18 +1965,14 @@ static void free_arguments(void) {
cpu_set_reset(&arg_cpu_affinity);
}
-static int load_configuration(int argc, char **argv, const char **ret_error_message) {
+static int parse_configuration(void) {
int r;
- assert(ret_error_message);
-
arg_default_tasks_max = system_tasks_max_scale(DEFAULT_TASKS_MAX_PERCENTAGE, 100U);
r = parse_config_file();
- if (r < 0) {
- *ret_error_message = "Failed to parse config file";
- return r;
- }
+ if (r < 0)
+ log_warning_errno(r, "Failed to parse config file, ignoring: %m");
if (arg_system) {
r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, 0);
@@ -1987,6 +1983,16 @@ static int load_configuration(int argc, char **argv, const char **ret_error_mess
/* Note that this also parses bits from the kernel command line, including "debug". */
log_parse_environment();
+ return 0;
+}
+
+static int load_configuration(int argc, char **argv, const char **ret_error_message) {
+ int r;
+
+ assert(ret_error_message);
+
+ (void) parse_configuration();
+
r = parse_argv(argc, argv);
if (r < 0) {
*ret_error_message = "Failed to parse commandline arguments";

View File

@ -0,0 +1,208 @@
From 0387294ba41ceaf80c79621409aab9508732bda0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Fri, 24 May 2019 09:41:44 +0200
Subject: [PATCH] pid1: when reloading configuration, forget old settings
If we had a configuration setting from a configuration file, and it was
removed, we'd still remember the old value, because there's was no mechanism to
"reset" everything, just to assign new values.
Note that the effect of this is limited. For settings that have an "ongoing" effect,
like systemd.confirm_spawn, the new value is simply used. But some settings can only
be set at start.
In particular, CPUAffinity= will be updated if set to a new value, but if
CPUAffinity= is fully removed, it will not be reset, simply because we don't
know what to reset it to. We might have inherited a setting, or we might have
set it ourselves. In principle we could remember the "original" value that was
set when we were executed, but propagate this over reloads and reexecs, but
that would be a lot of work for little gain. So this corner case of removal of
CPUAffinity= is not handled fully, and a reboot is needed to execute the
change. As a work-around, a full mask of CPUAffinity=0-8191 can be specified.
(cherry picked from commit fb39af4ce42d7ef9af63009f271f404038703704)
Related: #1734787
---
src/core/main.c | 139 +++++++++++++++++++++++++++++++++---------------
1 file changed, 95 insertions(+), 44 deletions(-)
diff --git a/src/core/main.c b/src/core/main.c
index 9a9f145080..c74dc641c1 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -88,46 +88,52 @@ static enum {
ACTION_DUMP_CONFIGURATION_ITEMS,
ACTION_DUMP_BUS_PROPERTIES,
} arg_action = ACTION_RUN;
-static char *arg_default_unit = NULL;
-static bool arg_system = false;
-static bool arg_dump_core = true;
-static int arg_crash_chvt = -1;
-static bool arg_crash_shell = false;
-static bool arg_crash_reboot = false;
-static char *arg_confirm_spawn = NULL;
-static ShowStatus arg_show_status = _SHOW_STATUS_UNSET;
-static bool arg_switched_root = false;
-static bool arg_no_pager = false;
-static bool arg_service_watchdogs = true;
+
+/* Those variables are initalized to 0 automatically, so we avoid uninitialized memory access.
+ * Real defaults are assigned in reset_arguments() below. */
+static char *arg_default_unit;
+static bool arg_system;
+static bool arg_dump_core;
+static int arg_crash_chvt;
+static bool arg_crash_shell;
+static bool arg_crash_reboot;
+static char *arg_confirm_spawn;
+static ShowStatus arg_show_status;
+static bool arg_switched_root;
+static bool arg_no_pager;
+static bool arg_service_watchdogs;
static char ***arg_join_controllers = NULL;
-static ExecOutput arg_default_std_output = EXEC_OUTPUT_JOURNAL;
-static ExecOutput arg_default_std_error = EXEC_OUTPUT_INHERIT;
-static usec_t arg_default_restart_usec = DEFAULT_RESTART_USEC;
-static usec_t arg_default_timeout_start_usec = DEFAULT_TIMEOUT_USEC;
-static usec_t arg_default_timeout_stop_usec = DEFAULT_TIMEOUT_USEC;
-static usec_t arg_default_start_limit_interval = DEFAULT_START_LIMIT_INTERVAL;
-static unsigned arg_default_start_limit_burst = DEFAULT_START_LIMIT_BURST;
-static usec_t arg_runtime_watchdog = 0;
-static usec_t arg_shutdown_watchdog = 10 * USEC_PER_MINUTE;
-static char *arg_watchdog_device = NULL;
-static char **arg_default_environment = NULL;
-static struct rlimit *arg_default_rlimit[_RLIMIT_MAX] = {};
-static uint64_t arg_capability_bounding_set = CAP_ALL;
-static bool arg_no_new_privs = false;
-static nsec_t arg_timer_slack_nsec = NSEC_INFINITY;
-static usec_t arg_default_timer_accuracy_usec = 1 * USEC_PER_MINUTE;
-static Set* arg_syscall_archs = NULL;
-static FILE* arg_serialization = NULL;
-static bool arg_default_cpu_accounting = false;
-static bool arg_default_io_accounting = false;
-static bool arg_default_ip_accounting = false;
-static bool arg_default_blockio_accounting = false;
-static bool arg_default_memory_accounting = MEMORY_ACCOUNTING_DEFAULT;
-static bool arg_default_tasks_accounting = true;
-static uint64_t arg_default_tasks_max = UINT64_MAX;
-static sd_id128_t arg_machine_id = {};
-static EmergencyAction arg_cad_burst_action = EMERGENCY_ACTION_REBOOT_FORCE;
-static CPUSet arg_cpu_affinity = {};
+static ExecOutput arg_default_std_output;
+static ExecOutput arg_default_std_error;
+static usec_t arg_default_restart_usec;
+static usec_t arg_default_timeout_start_usec;
+static usec_t arg_default_timeout_stop_usec;
+static usec_t arg_default_timeout_abort_usec;
+static bool arg_default_timeout_abort_set;
+static usec_t arg_default_start_limit_interval;
+static unsigned arg_default_start_limit_burst;
+static usec_t arg_runtime_watchdog;
+static usec_t arg_shutdown_watchdog;
+static char *arg_early_core_pattern;
+static char *arg_watchdog_device;
+static char **arg_default_environment;
+static struct rlimit *arg_default_rlimit[_RLIMIT_MAX];
+static uint64_t arg_capability_bounding_set;
+static bool arg_no_new_privs;
+static nsec_t arg_timer_slack_nsec;
+static usec_t arg_default_timer_accuracy_usec;
+static Set* arg_syscall_archs;
+static FILE* arg_serialization;
+static int arg_default_cpu_accounting;
+static bool arg_default_io_accounting;
+static bool arg_default_ip_accounting;
+static bool arg_default_blockio_accounting;
+static bool arg_default_memory_accounting;
+static bool arg_default_tasks_accounting;
+static uint64_t arg_default_tasks_max;
+static sd_id128_t arg_machine_id;
+static EmergencyAction arg_cad_burst_action;
+static CPUSet arg_cpu_affinity;
static int parse_configuration(void);
@@ -1951,17 +1957,59 @@ static int do_queue_default_job(
return 0;
}
-static void free_arguments(void) {
-
- /* Frees all arg_* variables, with the exception of arg_serialization */
- rlimit_free_all(arg_default_rlimit);
+static void reset_arguments(void) {
+ /* Frees/resets arg_* variables, with a few exceptions commented below. */
arg_default_unit = mfree(arg_default_unit);
+
+ /* arg_system — ignore */
+
+ arg_dump_core = true;
+ arg_crash_chvt = -1;
+ arg_crash_shell = false;
+ arg_crash_reboot = false;
arg_confirm_spawn = mfree(arg_confirm_spawn);
arg_join_controllers = strv_free_free(arg_join_controllers);
+ arg_show_status = _SHOW_STATUS_UNSET;
+ arg_switched_root = false;
+ arg_no_pager = false;
+ arg_service_watchdogs = true;
+ arg_default_std_output = EXEC_OUTPUT_JOURNAL;
+ arg_default_std_error = EXEC_OUTPUT_INHERIT;
+ arg_default_restart_usec = DEFAULT_RESTART_USEC;
+ arg_default_timeout_start_usec = DEFAULT_TIMEOUT_USEC;
+ arg_default_timeout_stop_usec = DEFAULT_TIMEOUT_USEC;
+ arg_default_timeout_abort_usec = DEFAULT_TIMEOUT_USEC;
+ arg_default_timeout_abort_set = false;
+ arg_default_start_limit_interval = DEFAULT_START_LIMIT_INTERVAL;
+ arg_default_start_limit_burst = DEFAULT_START_LIMIT_BURST;
+ arg_runtime_watchdog = 0;
+ arg_shutdown_watchdog = 10 * USEC_PER_MINUTE;
+ arg_early_core_pattern = NULL;
+ arg_watchdog_device = NULL;
+
arg_default_environment = strv_free(arg_default_environment);
+ rlimit_free_all(arg_default_rlimit);
+
+ arg_capability_bounding_set = CAP_ALL;
+ arg_no_new_privs = false;
+ arg_timer_slack_nsec = NSEC_INFINITY;
+ arg_default_timer_accuracy_usec = 1 * USEC_PER_MINUTE;
+
arg_syscall_archs = set_free(arg_syscall_archs);
+ /* arg_serialization — ignore */
+
+ arg_default_cpu_accounting = -1;
+ arg_default_io_accounting = false;
+ arg_default_ip_accounting = false;
+ arg_default_blockio_accounting = false;
+ arg_default_memory_accounting = MEMORY_ACCOUNTING_DEFAULT;
+ arg_default_tasks_accounting = true;
+ arg_default_tasks_max = UINT64_MAX;
+ arg_machine_id = (sd_id128_t) {};
+ arg_cad_burst_action = EMERGENCY_ACTION_REBOOT_FORCE;
+
cpu_set_reset(&arg_cpu_affinity);
}
@@ -1970,6 +2018,9 @@ static int parse_configuration(void) {
arg_default_tasks_max = system_tasks_max_scale(DEFAULT_TASKS_MAX_PERCENTAGE, 100U);
+ /* Assign configuration defaults */
+ reset_arguments();
+
r = parse_config_file();
if (r < 0)
log_warning_errno(r, "Failed to parse config file, ignoring: %m");
@@ -2460,7 +2511,7 @@ finish:
m = manager_free(m);
}
- free_arguments();
+ reset_arguments();
mac_selinux_finish();
if (reexecute)

View File

@ -0,0 +1,114 @@
From 5e6b616ed2708391752ba8c45f183ceb38573d7d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Tue, 28 May 2019 21:38:41 +0200
Subject: [PATCH] test-execute: use CPUSet too
cpu_set_malloc() was the last user. It doesn't seem useful to keep
it just to save the allocation of a few hundred bytes in a test, so
it is dropped and a fixed maximum is allocated (1024 bytes).
(cherry picked from commit 167a776dbe9d033523bd6881e5a695f2155dc321)
Related: #1734787
---
src/basic/cpu-set-util.c | 31 +------------------------------
src/basic/cpu-set-util.h | 3 +--
src/test/test-execute.c | 13 ++++++-------
3 files changed, 8 insertions(+), 39 deletions(-)
diff --git a/src/basic/cpu-set-util.c b/src/basic/cpu-set-util.c
index 1803539ac6..c297eab032 100644
--- a/src/basic/cpu-set-util.c
+++ b/src/basic/cpu-set-util.c
@@ -37,36 +37,7 @@ char* cpu_set_to_string(const CPUSet *a) {
return TAKE_PTR(str) ?: strdup("");
}
-cpu_set_t* cpu_set_malloc(unsigned *ncpus) {
- cpu_set_t *c;
- unsigned n = 1024;
-
- /* Allocates the cpuset in the right size */
-
- for (;;) {
- c = CPU_ALLOC(n);
- if (!c)
- return NULL;
-
- if (sched_getaffinity(0, CPU_ALLOC_SIZE(n), c) >= 0) {
- CPU_ZERO_S(CPU_ALLOC_SIZE(n), c);
-
- if (ncpus)
- *ncpus = n;
-
- return c;
- }
-
- CPU_FREE(c);
-
- if (errno != EINVAL)
- return NULL;
-
- n *= 2;
- }
-}
-
-static int cpu_set_realloc(CPUSet *cpu_set, unsigned ncpus) {
+int cpu_set_realloc(CPUSet *cpu_set, unsigned ncpus) {
size_t need;
assert(cpu_set);
diff --git a/src/basic/cpu-set-util.h b/src/basic/cpu-set-util.h
index 9b026aca09..b54e737110 100644
--- a/src/basic/cpu-set-util.h
+++ b/src/basic/cpu-set-util.h
@@ -12,8 +12,6 @@
DEFINE_TRIVIAL_CLEANUP_FUNC(cpu_set_t*, CPU_FREE);
#define _cleanup_cpu_free_ _cleanup_(CPU_FREEp)
-cpu_set_t* cpu_set_malloc(unsigned *ncpus);
-
/* This wraps the libc interface with a variable to keep the allocated size. */
typedef struct CPUSet {
cpu_set_t *set;
@@ -30,6 +28,7 @@ static inline void cpu_set_reset(CPUSet *a) {
int cpu_set_add_all(CPUSet *a, const CPUSet *b);
char* cpu_set_to_string(const CPUSet *a);
+int cpu_set_realloc(CPUSet *cpu_set, unsigned ncpus);
int parse_cpu_set_full(
const char *rvalue,
CPUSet *cpu_set,
diff --git a/src/test/test-execute.c b/src/test/test-execute.c
index fa8efdddd2..6c22995b1e 100644
--- a/src/test/test-execute.c
+++ b/src/test/test-execute.c
@@ -144,13 +144,12 @@ static void test_exec_bindpaths(Manager *m) {
}
static void test_exec_cpuaffinity(Manager *m) {
- _cleanup_cpu_free_ cpu_set_t *c = NULL;
- unsigned n;
+ _cleanup_(cpu_set_reset) CPUSet c = {};
- assert_se(c = cpu_set_malloc(&n));
- assert_se(sched_getaffinity(0, CPU_ALLOC_SIZE(n), c) >= 0);
+ assert_se(cpu_set_realloc(&c, 8192) >= 0); /* just allocate the maximum possible size */
+ assert_se(sched_getaffinity(0, c.allocated, c.set) >= 0);
- if (CPU_ISSET_S(0, CPU_ALLOC_SIZE(n), c) == 0) {
+ if (!CPU_ISSET_S(0, c.allocated, c.set)) {
log_notice("Cannot use CPU 0, skipping %s", __func__);
return;
}
@@ -158,8 +157,8 @@ static void test_exec_cpuaffinity(Manager *m) {
test(m, "exec-cpuaffinity1.service", 0, CLD_EXITED);
test(m, "exec-cpuaffinity2.service", 0, CLD_EXITED);
- if (CPU_ISSET_S(1, CPU_ALLOC_SIZE(n), c) == 0 ||
- CPU_ISSET_S(2, CPU_ALLOC_SIZE(n), c) == 0) {
+ if (!CPU_ISSET_S(1, c.allocated, c.set) ||
+ !CPU_ISSET_S(2, c.allocated, c.set)) {
log_notice("Cannot use CPU 1 or 2, skipping remaining tests in %s", __func__);
return;
}

View File

@ -0,0 +1,26 @@
From 7aa32093c3dfc4bf7298f02be553e95c40d7c211 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Tue, 28 May 2019 21:40:10 +0200
Subject: [PATCH] shared/cpu-set-util: drop now-unused cleanup function
(cherry picked from commit cb0d3acf55ef335001cac5dd9c335ec5e75e9b56)
Related: #1734787
---
src/basic/cpu-set-util.h | 3 ---
1 file changed, 3 deletions(-)
diff --git a/src/basic/cpu-set-util.h b/src/basic/cpu-set-util.h
index b54e737110..68a73bf9f7 100644
--- a/src/basic/cpu-set-util.h
+++ b/src/basic/cpu-set-util.h
@@ -9,9 +9,6 @@
#include "macro.h"
-DEFINE_TRIVIAL_CLEANUP_FUNC(cpu_set_t*, CPU_FREE);
-#define _cleanup_cpu_free_ _cleanup_(CPU_FREEp)
-
/* This wraps the libc interface with a variable to keep the allocated size. */
typedef struct CPUSet {
cpu_set_t *set;

View File

@ -0,0 +1,126 @@
From daa0243fda679c8af723648b8b1e501fc55b0ada Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Wed, 22 May 2019 13:55:49 +0200
Subject: [PATCH] shared/cpu-set-util: make transfer of cpu_set_t over bus
endian safe
(cherry picked from commit c367f996f5f091a63f812f0140b304c649be77fc)
Related: #1734787
---
src/basic/cpu-set-util.c | 38 ++++++++++++++++++++++++++++++++++++++
src/basic/cpu-set-util.h | 3 +++
src/core/dbus-execute.c | 6 +++++-
src/shared/bus-unit-util.c | 8 +++++++-
4 files changed, 53 insertions(+), 2 deletions(-)
diff --git a/src/basic/cpu-set-util.c b/src/basic/cpu-set-util.c
index c297eab032..74e35e57dd 100644
--- a/src/basic/cpu-set-util.c
+++ b/src/basic/cpu-set-util.c
@@ -209,3 +209,41 @@ int cpus_in_affinity_mask(void) {
n *= 2;
}
}
+
+int cpu_set_to_dbus(const CPUSet *set, uint8_t **ret, size_t *allocated) {
+ uint8_t *out;
+
+ assert(set);
+ assert(ret);
+
+ out = new0(uint8_t, set->allocated);
+ if (!out)
+ return -ENOMEM;
+
+ for (unsigned cpu = 0; cpu < set->allocated * 8; cpu++)
+ if (CPU_ISSET_S(cpu, set->allocated, set->set))
+ out[cpu / 8] |= 1u << (cpu % 8);
+
+ *ret = out;
+ *allocated = set->allocated;
+ return 0;
+}
+
+int cpu_set_from_dbus(const uint8_t *bits, size_t size, CPUSet *set) {
+ _cleanup_(cpu_set_reset) CPUSet s = {};
+ int r;
+
+ assert(bits);
+ assert(set);
+
+ for (unsigned cpu = size * 8; cpu > 0; cpu--)
+ if (bits[(cpu - 1) / 8] & (1u << ((cpu - 1) % 8))) {
+ r = cpu_set_add(&s, cpu - 1);
+ if (r < 0)
+ return r;
+ }
+
+ *set = s;
+ s = (CPUSet) {};
+ return 0;
+}
diff --git a/src/basic/cpu-set-util.h b/src/basic/cpu-set-util.h
index 68a73bf9f7..415c6ca295 100644
--- a/src/basic/cpu-set-util.h
+++ b/src/basic/cpu-set-util.h
@@ -46,4 +46,7 @@ static inline int parse_cpu_set(const char *rvalue, CPUSet *cpu_set){
return parse_cpu_set_full(rvalue, cpu_set, false, NULL, NULL, 0, NULL);
}
+int cpu_set_to_dbus(const CPUSet *set, uint8_t **ret, size_t *allocated);
+int cpu_set_from_dbus(const uint8_t *bits, size_t size, CPUSet *set);
+
int cpus_in_affinity_mask(void);
diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
index 08946627e3..50ea71a281 100644
--- a/src/core/dbus-execute.c
+++ b/src/core/dbus-execute.c
@@ -1553,18 +1553,22 @@ int bus_exec_context_set_transient_property(
if (streq(name, "CPUAffinity")) {
const void *a;
size_t n;
+ _cleanup_(cpu_set_reset) CPUSet set = {};
r = sd_bus_message_read_array(message, 'y', &a, &n);
if (r < 0)
return r;
+ r = cpu_set_from_dbus(a, n, &set);
+ if (r < 0)
+ return r;
+
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
if (n == 0) {
cpu_set_reset(&c->cpu_set);
unit_write_settingf(u, flags, name, "%s=", name);
} else {
_cleanup_free_ char *str = NULL;
- const CPUSet set = {(cpu_set_t*) a, n};
str = cpu_set_to_string(&set);
if (!str)
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
index 75b4aace84..ec8732c226 100644
--- a/src/shared/bus-unit-util.c
+++ b/src/shared/bus-unit-util.c
@@ -933,12 +933,18 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
if (streq(field, "CPUAffinity")) {
_cleanup_(cpu_set_reset) CPUSet cpuset = {};
+ _cleanup_free_ uint8_t *array = NULL;
+ size_t allocated;
r = parse_cpu_set(eq, &cpuset);
if (r < 0)
return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
- return bus_append_byte_array(m, field, cpuset.set, cpuset.allocated);
+ r = cpu_set_to_dbus(&cpuset, &array, &allocated);
+ if (r < 0)
+ return log_error_errno(r, "Failed to serialize CPUAffinity: %m");
+
+ return bus_append_byte_array(m, field, array, allocated);
}
if (STR_IN_SET(field, "RestrictAddressFamilies", "SystemCallFilter")) {

View File

@ -0,0 +1,61 @@
From fd65eadbbcc068171ee9164610fd1c2016b3bf59 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Wed, 29 May 2019 09:44:16 +0200
Subject: [PATCH] test-cpu-set-util: add test for dbus conversions
(cherry picked from commit 1bf0d6c28f8c884e187c7dacc1a969c0763ff4e3)
Related: #1734787
---
src/test/test-cpu-set-util.c | 31 +++++++++++++++++++++++++++++++
1 file changed, 31 insertions(+)
diff --git a/src/test/test-cpu-set-util.c b/src/test/test-cpu-set-util.c
index 81f67647e8..cae51ad7d9 100644
--- a/src/test/test-cpu-set-util.c
+++ b/src/test/test-cpu-set-util.c
@@ -181,6 +181,36 @@ static void test_parse_cpu_set_extend(void) {
log_info("cpu_set_to_string: (null)");
}
+static void test_cpu_set_to_from_dbus(void) {
+ _cleanup_(cpu_set_reset) CPUSet c = {}, c2 = {};
+ _cleanup_free_ char *s = NULL;
+
+ log_info("/* %s */", __func__);
+
+ assert_se(parse_cpu_set_extend("1 3 8 100-200", &c, true, NULL, "fake", 1, "CPUAffinity") == 0);
+ assert_se(s = cpu_set_to_string(&c));
+ log_info("cpu_set_to_string: %s", s);
+ assert_se(CPU_COUNT_S(c.allocated, c.set) == 104);
+
+ _cleanup_free_ uint8_t *array = NULL;
+ size_t allocated;
+ static const char expected[32] =
+ "\x0A\x01\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\xF0\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\x01";
+
+ assert_se(cpu_set_to_dbus(&c, &array, &allocated) == 0);
+ assert_se(array);
+ assert_se(allocated == c.allocated);
+
+ assert(memcmp(array, expected, sizeof expected) == 0);
+
+ assert_se(cpu_set_from_dbus(array, allocated, &c2) == 0);
+ assert_se(c2.set);
+ assert_se(c2.allocated == c.allocated);
+ assert_se(memcmp(c.set, c2.set, c.allocated) == 0);
+}
+
static void test_cpus_in_affinity_mask(void) {
int r;
@@ -201,6 +231,7 @@ int main(int argc, char *argv[]) {
test_parse_cpu_set();
test_parse_cpu_set_extend();
test_cpus_in_affinity_mask();
+ test_cpu_set_to_from_dbus();
return 0;
}

View File

@ -0,0 +1,203 @@
From 93777a6dd8c12d5cba094694bf7ed6e8c06c2d6d Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Thu, 23 May 2019 14:27:18 +0200
Subject: [PATCH] shared/cpu-set-util: introduce cpu_set_to_range()
(cherry picked from commit 71b28519b55b496237146f9bcb5a627455f15f7e)
Related: #1734787
---
src/basic/cpu-set-util.c | 37 ++++++++++++++++++++++++++
src/basic/cpu-set-util.h | 2 ++
src/test/test-cpu-set-util.c | 50 ++++++++++++++++++++++++++++++++++++
3 files changed, 89 insertions(+)
diff --git a/src/basic/cpu-set-util.c b/src/basic/cpu-set-util.c
index 74e35e57dd..bff39ec143 100644
--- a/src/basic/cpu-set-util.c
+++ b/src/basic/cpu-set-util.c
@@ -37,6 +37,43 @@ char* cpu_set_to_string(const CPUSet *a) {
return TAKE_PTR(str) ?: strdup("");
}
+char *cpu_set_to_range_string(const CPUSet *set) {
+ unsigned range_start = 0, range_end;
+ _cleanup_free_ char *str = NULL;
+ size_t allocated = 0, len = 0;
+ bool in_range = false;
+ int r;
+
+ for (unsigned i = 0; i < set->allocated * 8; i++)
+ if (CPU_ISSET_S(i, set->allocated, set->set)) {
+ if (in_range)
+ range_end++;
+ else {
+ range_start = range_end = i;
+ in_range = true;
+ }
+ } else if (in_range) {
+ in_range = false;
+
+ if (!GREEDY_REALLOC(str, allocated, len + 2 + 2 * DECIMAL_STR_MAX(unsigned)))
+ return NULL;
+
+ r = sprintf(str + len, len > 0 ? " %d-%d" : "%d-%d", range_start, range_end);
+ assert_se(r > 0);
+ len += r;
+ }
+
+ if (in_range) {
+ if (!GREEDY_REALLOC(str, allocated, len + 2 + 2 * DECIMAL_STR_MAX(int)))
+ return NULL;
+
+ r = sprintf(str + len, len > 0 ? " %d-%d" : "%d-%d", range_start, range_end);
+ assert_se(r > 0);
+ }
+
+ return TAKE_PTR(str) ?: strdup("");
+}
+
int cpu_set_realloc(CPUSet *cpu_set, unsigned ncpus) {
size_t need;
diff --git a/src/basic/cpu-set-util.h b/src/basic/cpu-set-util.h
index 415c6ca295..ec640b2ec9 100644
--- a/src/basic/cpu-set-util.h
+++ b/src/basic/cpu-set-util.h
@@ -25,7 +25,9 @@ static inline void cpu_set_reset(CPUSet *a) {
int cpu_set_add_all(CPUSet *a, const CPUSet *b);
char* cpu_set_to_string(const CPUSet *a);
+char *cpu_set_to_range_string(const CPUSet *a);
int cpu_set_realloc(CPUSet *cpu_set, unsigned ncpus);
+
int parse_cpu_set_full(
const char *rvalue,
CPUSet *cpu_set,
diff --git a/src/test/test-cpu-set-util.c b/src/test/test-cpu-set-util.c
index cae51ad7d9..0d2741cd43 100644
--- a/src/test/test-cpu-set-util.c
+++ b/src/test/test-cpu-set-util.c
@@ -4,6 +4,7 @@
#include "alloc-util.h"
#include "cpu-set-util.h"
+#include "string-util.h"
#include "macro.h"
static void test_parse_cpu_set(void) {
@@ -13,6 +14,22 @@ static void test_parse_cpu_set(void) {
log_info("/* %s */", __func__);
+ /* Single value */
+ assert_se(parse_cpu_set_full("0", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
+ assert_se(c.set);
+ assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
+ assert_se(CPU_ISSET_S(0, c.allocated, c.set));
+ assert_se(CPU_COUNT_S(c.allocated, c.set) == 1);
+
+ assert_se(str = cpu_set_to_string(&c));
+ log_info("cpu_set_to_string: %s", str);
+ str = mfree(str);
+ assert_se(str = cpu_set_to_range_string(&c));
+ log_info("cpu_set_to_range_string: %s", str);
+ assert_se(streq(str, "0-0"));
+ str = mfree(str);
+ cpu_set_reset(&c);
+
/* Simple range (from CPUAffinity example) */
assert_se(parse_cpu_set_full("1 2", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
assert_se(c.set);
@@ -24,6 +41,10 @@ static void test_parse_cpu_set(void) {
assert_se(str = cpu_set_to_string(&c));
log_info("cpu_set_to_string: %s", str);
str = mfree(str);
+ assert_se(str = cpu_set_to_range_string(&c));
+ log_info("cpu_set_to_range_string: %s", str);
+ assert_se(streq(str, "1-2"));
+ str = mfree(str);
cpu_set_reset(&c);
/* A more interesting range */
@@ -34,9 +55,14 @@ static void test_parse_cpu_set(void) {
assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
for (cpu = 8; cpu < 12; cpu++)
assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
+
assert_se(str = cpu_set_to_string(&c));
log_info("cpu_set_to_string: %s", str);
str = mfree(str);
+ assert_se(str = cpu_set_to_range_string(&c));
+ log_info("cpu_set_to_range_string: %s", str);
+ assert_se(streq(str, "0-3 8-11"));
+ str = mfree(str);
cpu_set_reset(&c);
/* Quoted strings */
@@ -48,6 +74,10 @@ static void test_parse_cpu_set(void) {
assert_se(str = cpu_set_to_string(&c));
log_info("cpu_set_to_string: %s", str);
str = mfree(str);
+ assert_se(str = cpu_set_to_range_string(&c));
+ log_info("cpu_set_to_range_string: %s", str);
+ assert_se(streq(str, "8-11"));
+ str = mfree(str);
cpu_set_reset(&c);
/* Use commas as separators */
@@ -72,6 +102,10 @@ static void test_parse_cpu_set(void) {
assert_se(str = cpu_set_to_string(&c));
log_info("cpu_set_to_string: %s", str);
str = mfree(str);
+ assert_se(str = cpu_set_to_range_string(&c));
+ log_info("cpu_set_to_range_string: %s", str);
+ assert_se(streq(str, "0-7"));
+ str = mfree(str);
cpu_set_reset(&c);
/* Ranges */
@@ -98,6 +132,10 @@ static void test_parse_cpu_set(void) {
assert_se(str = cpu_set_to_string(&c));
log_info("cpu_set_to_string: %s", str);
str = mfree(str);
+ assert_se(str = cpu_set_to_range_string(&c));
+ log_info("cpu_set_to_range_string: %s", str);
+ assert_se(streq(str, "0-3 8-11"));
+ str = mfree(str);
cpu_set_reset(&c);
/* Negative range (returns empty cpu_set) */
@@ -115,6 +153,10 @@ static void test_parse_cpu_set(void) {
assert_se(str = cpu_set_to_string(&c));
log_info("cpu_set_to_string: %s", str);
str = mfree(str);
+ assert_se(str = cpu_set_to_range_string(&c));
+ log_info("cpu_set_to_range_string: %s", str);
+ assert_se(streq(str, "0-11"));
+ str = mfree(str);
cpu_set_reset(&c);
/* Mix ranges and individual CPUs */
@@ -128,6 +170,10 @@ static void test_parse_cpu_set(void) {
assert_se(str = cpu_set_to_string(&c));
log_info("cpu_set_to_string: %s", str);
str = mfree(str);
+ assert_se(str = cpu_set_to_range_string(&c));
+ log_info("cpu_set_to_range_string: %s", str);
+ assert_se(streq(str, "0-1 4-11"));
+ str = mfree(str);
cpu_set_reset(&c);
/* Garbage */
@@ -156,6 +202,10 @@ static void test_parse_cpu_set(void) {
assert_se(str = cpu_set_to_string(&c));
log_info("cpu_set_to_string: %s", str);
str = mfree(str);
+ assert_se(str = cpu_set_to_range_string(&c));
+ log_info("cpu_set_to_range_string: %s", str);
+ assert_se(streq(str, "8000-8191"));
+ str = mfree(str);
cpu_set_reset(&c);
}

View File

@ -0,0 +1,53 @@
From fb1244ef318e9f54628a7c13db9e2ffbc712dd38 Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Wed, 22 May 2019 17:14:21 +0200
Subject: [PATCH] systemctl: present CPUAffinity mask as a list of CPU index
ranges
(cherry picked from commit a047f4f10ed2f922d6079c033d24a443b0e95f38)
Related: #1734787
---
src/systemctl/systemctl.c | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index f072ad0c31..0154b300a3 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -30,6 +30,7 @@
#include "cgroup-show.h"
#include "cgroup-util.h"
#include "copy.h"
+#include "cpu-set-util.h"
#include "dropin.h"
#include "efivars.h"
#include "env-util.h"
@@ -4876,6 +4877,27 @@ static int print_property(const char *name, sd_bus_message *m, bool value, bool
print_prop(name, "%s", h);
+ return 1;
+ } else if (contents[0] == SD_BUS_TYPE_BYTE && streq(name, "CPUAffinity")) {
+ _cleanup_free_ char *affinity = NULL;
+ _cleanup_(cpu_set_reset) CPUSet set = {};
+ const void *a;
+ size_t n;
+
+ r = sd_bus_message_read_array(m, 'y', &a, &n);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ r = cpu_set_from_dbus(a, n, &set);
+ if (r < 0)
+ return log_error_errno(r, "Failed to deserialize CPUAffinity: %m");
+
+ affinity = cpu_set_to_range_string(&set);
+ if (!affinity)
+ return log_oom();
+
+ print_prop(name, "%s", affinity);
+
return 1;
}

View File

@ -0,0 +1,77 @@
From cabd9055d0d745f7de9625dec6c623d363dd3aa6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Wed, 29 May 2019 10:17:43 +0200
Subject: [PATCH] shared/cpu-set-util: only force range printing one time
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The idea is to have at least one range to make the new format clearly
distinguishable from the old. But it is enough to just do it once.
In particular, in case the affinity would be specified like 0, 2, 4, 6…,
this gives much shorter output.
(cherry picked from commit 1f57a176af5152d05719bf43740e87a47e37af50)
Related: #1734787
---
src/basic/cpu-set-util.c | 10 ++++++++--
src/test/test-cpu-set-util.c | 7 ++++---
2 files changed, 12 insertions(+), 5 deletions(-)
diff --git a/src/basic/cpu-set-util.c b/src/basic/cpu-set-util.c
index bff39ec143..5024290557 100644
--- a/src/basic/cpu-set-util.c
+++ b/src/basic/cpu-set-util.c
@@ -58,7 +58,10 @@ char *cpu_set_to_range_string(const CPUSet *set) {
if (!GREEDY_REALLOC(str, allocated, len + 2 + 2 * DECIMAL_STR_MAX(unsigned)))
return NULL;
- r = sprintf(str + len, len > 0 ? " %d-%d" : "%d-%d", range_start, range_end);
+ if (range_end > range_start || len == 0)
+ r = sprintf(str + len, len > 0 ? " %d-%d" : "%d-%d", range_start, range_end);
+ else
+ r = sprintf(str + len, len > 0 ? " %d" : "%d", range_start);
assert_se(r > 0);
len += r;
}
@@ -67,7 +70,10 @@ char *cpu_set_to_range_string(const CPUSet *set) {
if (!GREEDY_REALLOC(str, allocated, len + 2 + 2 * DECIMAL_STR_MAX(int)))
return NULL;
- r = sprintf(str + len, len > 0 ? " %d-%d" : "%d-%d", range_start, range_end);
+ if (range_end > range_start || len == 0)
+ r = sprintf(str + len, len > 0 ? " %d-%d" : "%d-%d", range_start, range_end);
+ else
+ r = sprintf(str + len, len > 0 ? " %d" : "%d", range_start);
assert_se(r > 0);
}
diff --git a/src/test/test-cpu-set-util.c b/src/test/test-cpu-set-util.c
index 0d2741cd43..995b981d25 100644
--- a/src/test/test-cpu-set-util.c
+++ b/src/test/test-cpu-set-util.c
@@ -31,19 +31,20 @@ static void test_parse_cpu_set(void) {
cpu_set_reset(&c);
/* Simple range (from CPUAffinity example) */
- assert_se(parse_cpu_set_full("1 2", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
+ assert_se(parse_cpu_set_full("1 2 4", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
assert_se(c.set);
assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
assert_se(CPU_ISSET_S(1, c.allocated, c.set));
assert_se(CPU_ISSET_S(2, c.allocated, c.set));
- assert_se(CPU_COUNT_S(c.allocated, c.set) == 2);
+ assert_se(CPU_ISSET_S(4, c.allocated, c.set));
+ assert_se(CPU_COUNT_S(c.allocated, c.set) == 3);
assert_se(str = cpu_set_to_string(&c));
log_info("cpu_set_to_string: %s", str);
str = mfree(str);
assert_se(str = cpu_set_to_range_string(&c));
log_info("cpu_set_to_range_string: %s", str);
- assert_se(streq(str, "1-2"));
+ assert_se(streq(str, "1-2 4"));
str = mfree(str);
cpu_set_reset(&c);

View File

@ -0,0 +1,36 @@
From b90f935f8d2268522480a7c12f7e2213a7a5e19d Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Fri, 31 May 2019 18:02:20 +0200
Subject: [PATCH] execute: dump CPUAffinity as a range string instead of a list
of CPUs
We do this already when printing the property in systemctl so be
consistent and do the same for systemd-analyze dump.
(cherry picked from commit e7fca352ba43988682a927de6b1f629b3f10a415)
Related: #1734787
---
src/core/execute.c | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/src/core/execute.c b/src/core/execute.c
index 22e5825905..bc26aa66e7 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -4098,11 +4098,10 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
}
if (c->cpu_set.set) {
- fprintf(f, "%sCPUAffinity:", prefix);
- for (i = 0; i < c->cpu_set.allocated * 8; i++)
- if (CPU_ISSET_S(i, c->cpu_set.allocated, c->cpu_set.set))
- fprintf(f, " %u", i);
- fputs("\n", f);
+ _cleanup_free_ char *affinity = NULL;
+
+ affinity = cpu_set_to_range_string(&c->cpu_set);
+ fprintf(f, "%sCPUAffinity: %s\n", prefix, affinity);
}
if (c->timer_slack_nsec != NSEC_INFINITY)

View File

@ -0,0 +1,95 @@
From 35894625624f0e8c7d3ca2c200861005c7ad4435 Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Mon, 3 Jun 2019 10:12:35 +0200
Subject: [PATCH] cpu-set-util: use %d-%d format in cpu_set_to_range_string()
only for actual ranges
(cherry picked from commit 71923237b18df35401626993d8a285cd998be78d)
Related: #1734787
---
src/basic/cpu-set-util.c | 4 ++--
src/test/test-cpu-set-util.c | 16 +++++++++-------
2 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/src/basic/cpu-set-util.c b/src/basic/cpu-set-util.c
index 5024290557..103b9703b3 100644
--- a/src/basic/cpu-set-util.c
+++ b/src/basic/cpu-set-util.c
@@ -58,7 +58,7 @@ char *cpu_set_to_range_string(const CPUSet *set) {
if (!GREEDY_REALLOC(str, allocated, len + 2 + 2 * DECIMAL_STR_MAX(unsigned)))
return NULL;
- if (range_end > range_start || len == 0)
+ if (range_end > range_start)
r = sprintf(str + len, len > 0 ? " %d-%d" : "%d-%d", range_start, range_end);
else
r = sprintf(str + len, len > 0 ? " %d" : "%d", range_start);
@@ -70,7 +70,7 @@ char *cpu_set_to_range_string(const CPUSet *set) {
if (!GREEDY_REALLOC(str, allocated, len + 2 + 2 * DECIMAL_STR_MAX(int)))
return NULL;
- if (range_end > range_start || len == 0)
+ if (range_end > range_start)
r = sprintf(str + len, len > 0 ? " %d-%d" : "%d-%d", range_start, range_end);
else
r = sprintf(str + len, len > 0 ? " %d" : "%d", range_start);
diff --git a/src/test/test-cpu-set-util.c b/src/test/test-cpu-set-util.c
index 995b981d25..9522582891 100644
--- a/src/test/test-cpu-set-util.c
+++ b/src/test/test-cpu-set-util.c
@@ -26,7 +26,7 @@ static void test_parse_cpu_set(void) {
str = mfree(str);
assert_se(str = cpu_set_to_range_string(&c));
log_info("cpu_set_to_range_string: %s", str);
- assert_se(streq(str, "0-0"));
+ assert_se(streq(str, "0"));
str = mfree(str);
cpu_set_reset(&c);
@@ -95,17 +95,19 @@ static void test_parse_cpu_set(void) {
cpu_set_reset(&c);
/* Commas with spaces (and trailing comma, space) */
- assert_se(parse_cpu_set_full("0, 1, 2, 3, 4, 5, 6, 7, ", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
+ assert_se(parse_cpu_set_full("0, 1, 2, 3, 4, 5, 6, 7, 63, ", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
- assert_se(CPU_COUNT_S(c.allocated, c.set) == 8);
+ assert_se(CPU_COUNT_S(c.allocated, c.set) == 9);
for (cpu = 0; cpu < 8; cpu++)
assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
+
+ assert_se(CPU_ISSET_S(63, c.allocated, c.set));
assert_se(str = cpu_set_to_string(&c));
log_info("cpu_set_to_string: %s", str);
str = mfree(str);
assert_se(str = cpu_set_to_range_string(&c));
log_info("cpu_set_to_range_string: %s", str);
- assert_se(streq(str, "0-7"));
+ assert_se(streq(str, "0-7 63"));
str = mfree(str);
cpu_set_reset(&c);
@@ -161,11 +163,11 @@ static void test_parse_cpu_set(void) {
cpu_set_reset(&c);
/* Mix ranges and individual CPUs */
- assert_se(parse_cpu_set_full("0,1 4-11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
+ assert_se(parse_cpu_set_full("0,2 4-11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
assert_se(CPU_COUNT_S(c.allocated, c.set) == 10);
assert_se(CPU_ISSET_S(0, c.allocated, c.set));
- assert_se(CPU_ISSET_S(1, c.allocated, c.set));
+ assert_se(CPU_ISSET_S(2, c.allocated, c.set));
for (cpu = 4; cpu < 12; cpu++)
assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
assert_se(str = cpu_set_to_string(&c));
@@ -173,7 +175,7 @@ static void test_parse_cpu_set(void) {
str = mfree(str);
assert_se(str = cpu_set_to_range_string(&c));
log_info("cpu_set_to_range_string: %s", str);
- assert_se(streq(str, "0-1 4-11"));
+ assert_se(streq(str, "0 2 4-11"));
str = mfree(str);
cpu_set_reset(&c);

View File

@ -0,0 +1,779 @@
From a735699a8287c19e043b7d2fe9a387a3938e1e2f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michal=20Sekleta=CC=81r?= <msekleta@redhat.com>
Date: Mon, 18 Nov 2019 12:50:11 +0100
Subject: [PATCH] core: introduce NUMAPolicy and NUMAMask options
Make possible to set NUMA allocation policy for manager. Manager's
policy is by default inherited to all forked off processes. However, it
is possible to override the policy on per-service basis. Currently we
support, these policies: default, prefer, bind, interleave, local.
See man 2 set_mempolicy for details on each policy.
Overall NUMA policy actually consists of two parts. Policy itself and
bitmask representing NUMA nodes where is policy effective. Node mask can
be specified using related option, NUMAMask. Default mask can be
overwritten on per-service level.
(cherry-picked from commit fe9c54b2188e6cd23262a319f96b13215f2c5e9c)
Resolves: #1734787
---
man/systemd-system.conf.xml | 19 ++++++
man/systemd.exec.xml | 28 +++++++++
meson.build | 4 ++
src/basic/cpu-set-util.c | 91 +++++++++++++++++++++++++++
src/basic/cpu-set-util.h | 28 +++++++++
src/basic/exit-status.c | 3 +
src/basic/exit-status.h | 1 +
src/basic/missing_syscall.h | 43 +++++++++++++
src/core/dbus-execute.c | 65 ++++++++++++++++++-
src/core/execute.c | 20 ++++++
src/core/execute.h | 1 +
src/core/load-fragment-gperf.gperf.m4 | 2 +
src/core/load-fragment.c | 28 +++++++++
src/core/load-fragment.h | 2 +
src/core/main.c | 27 ++++++++
src/core/system.conf.in | 2 +
src/shared/bus-unit-util.c | 28 +++++++++
src/systemctl/systemctl.c | 18 +++++-
18 files changed, 405 insertions(+), 5 deletions(-)
diff --git a/man/systemd-system.conf.xml b/man/systemd-system.conf.xml
index ab23779ec0..988c4e7665 100644
--- a/man/systemd-system.conf.xml
+++ b/man/systemd-system.conf.xml
@@ -132,6 +132,25 @@
anymore.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>NUMAPolicy=</varname></term>
+
+ <listitem><para>Configures the NUMA memory policy for the service manager and the default NUMA memory policy
+ for all forked off processes. Individual services may override the default policy with the
+ <varname>NUMAPolicy=</varname> setting in unit files, see
+ <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>NUMAMask=</varname></term>
+
+ <listitem><para>Configures the NUMA node mask that will be associated with the selected NUMA policy. Note that
+ <option>default</option> and <option>local</option> NUMA policies don't require explicit NUMA node mask and
+ value of the option can be empty. Similarly to <varname>NUMAPolicy=</varname>, value can be overriden
+ by individual services in unit files, see
+ <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para></listitem>
+ </varlistentry>
+
<varlistentry>
<term><varname>RuntimeWatchdogSec=</varname></term>
<term><varname>ShutdownWatchdogSec=</varname></term>
diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml
index 342b8385bc..87fb8b34f4 100644
--- a/man/systemd.exec.xml
+++ b/man/systemd.exec.xml
@@ -710,6 +710,28 @@ CapabilityBoundingSet=~CAP_B CAP_C</programlisting>
details.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>NUMAPolicy=</varname></term>
+
+ <listitem><para>Controls the NUMA memory policy of the executed processes. Takes a policy type, one of:
+ <option>default</option>, <option>preferred</option>, <option>bind</option>, <option>interleave</option> and
+ <option>local</option>. A list of NUMA nodes that should be associated with the policy must be specified
+ in <varname>NUMAMask=</varname>. For more details on each policy please see,
+ <citerefentry><refentrytitle>set_mempolicy</refentrytitle><manvolnum>2</manvolnum></citerefentry>. For overall
+ overview of NUMA support in Linux see,
+ <citerefentry><refentrytitle>numa</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>NUMAMask=</varname></term>
+
+ <listitem><para>Controls the NUMA node list which will be applied alongside with selected NUMA policy.
+ Takes a list of NUMA nodes and has the same syntax as a list of CPUs for <varname>CPUAffinity=</varname>
+ option. Note that the list of NUMA nodes is not required for <option>default</option> and <option>local</option>
+ policies and for <option>preferred</option> policy we expect a single NUMA node.</para></listitem>
+ </varlistentry>
+
<varlistentry>
<term><varname>IOSchedulingClass=</varname></term>
@@ -2709,6 +2731,12 @@ StandardInputData=SWNrIHNpdHplIGRhIHVuJyBlc3NlIEtsb3BzLAp1ZmYgZWVtYWwga2xvcHAncy
<entry><constant>EXIT_CONFIGURATION_DIRECTORY</constant></entry>
<entry>Failed to set up unit's configuration directory. See <varname>ConfigurationDirectory=</varname> above.</entry>
</row>
+ <row>
+ <entry>242</entry>
+ <entry><constant>EXIT_NUMA_POLICY</constant></entry>
+ <entry>Failed to set up unit's NUMA memory policy. See <varname>NUMAPolicy=</varname> and <varname>NUMAMask=</varname>above.</entry>
+ </row>
+
</tbody>
</tgroup>
</table>
diff --git a/meson.build b/meson.build
index 613a5133b6..fe82ca4ac2 100644
--- a/meson.build
+++ b/meson.build
@@ -501,6 +501,10 @@ foreach ident : [
#include <unistd.h>'''],
['explicit_bzero' , '''#include <string.h>'''],
['reallocarray', '''#include <malloc.h>'''],
+ ['set_mempolicy', '''#include <stdlib.h>
+ #include <unistd.h>'''],
+ ['get_mempolicy', '''#include <stdlib.h>
+ #include <unistd.h>'''],
]
have = cc.has_function(ident[0], prefix : ident[1], args : '-D_GNU_SOURCE')
diff --git a/src/basic/cpu-set-util.c b/src/basic/cpu-set-util.c
index 103b9703b3..36cb017ae7 100644
--- a/src/basic/cpu-set-util.c
+++ b/src/basic/cpu-set-util.c
@@ -10,11 +10,17 @@
#include "alloc-util.h"
#include "cpu-set-util.h"
+#include "dirent-util.h"
#include "extract-word.h"
+#include "fd-util.h"
#include "log.h"
#include "macro.h"
+#include "missing.h"
#include "parse-util.h"
+#include "stat-util.h"
#include "string-util.h"
+#include "string-table.h"
+#include "strv.h"
#include "util.h"
char* cpu_set_to_string(const CPUSet *a) {
@@ -290,3 +296,88 @@ int cpu_set_from_dbus(const uint8_t *bits, size_t size, CPUSet *set) {
s = (CPUSet) {};
return 0;
}
+
+bool numa_policy_is_valid(const NUMAPolicy *policy) {
+ assert(policy);
+
+ if (!mpol_is_valid(numa_policy_get_type(policy)))
+ return false;
+
+ if (!policy->nodes.set &&
+ !IN_SET(numa_policy_get_type(policy), MPOL_DEFAULT, MPOL_LOCAL, MPOL_PREFERRED))
+ return false;
+
+ if (policy->nodes.set &&
+ numa_policy_get_type(policy) == MPOL_PREFERRED &&
+ CPU_COUNT_S(policy->nodes.allocated, policy->nodes.set) != 1)
+ return false;
+
+ return true;
+}
+
+static int numa_policy_to_mempolicy(const NUMAPolicy *policy, unsigned long *ret_maxnode, unsigned long **ret_nodes) {
+ unsigned node, bits = 0, ulong_bits;
+ _cleanup_free_ unsigned long *out = NULL;
+
+ assert(policy);
+ assert(ret_maxnode);
+ assert(ret_nodes);
+
+ if (IN_SET(numa_policy_get_type(policy), MPOL_DEFAULT, MPOL_LOCAL) ||
+ (numa_policy_get_type(policy) == MPOL_PREFERRED && !policy->nodes.set)) {
+ *ret_nodes = NULL;
+ *ret_maxnode = 0;
+ return 0;
+ }
+
+ bits = policy->nodes.allocated * 8;
+ ulong_bits = sizeof(unsigned long) * 8;
+
+ out = new0(unsigned long, DIV_ROUND_UP(policy->nodes.allocated, sizeof(unsigned long)));
+ if (!out)
+ return -ENOMEM;
+
+ /* We don't make any assumptions about internal type libc is using to store NUMA node mask.
+ Hence we need to convert the node mask to the representation expected by set_mempolicy() */
+ for (node = 0; node < bits; node++)
+ if (CPU_ISSET_S(node, policy->nodes.allocated, policy->nodes.set))
+ out[node / ulong_bits] |= 1ul << (node % ulong_bits);
+
+ *ret_nodes = TAKE_PTR(out);
+ *ret_maxnode = bits + 1;
+ return 0;
+}
+
+int apply_numa_policy(const NUMAPolicy *policy) {
+ int r;
+ _cleanup_free_ unsigned long *nodes = NULL;
+ unsigned long maxnode;
+
+ assert(policy);
+
+ if (get_mempolicy(NULL, NULL, 0, 0, 0) < 0 && errno == ENOSYS)
+ return -EOPNOTSUPP;
+
+ if (!numa_policy_is_valid(policy))
+ return -EINVAL;
+
+ r = numa_policy_to_mempolicy(policy, &maxnode, &nodes);
+ if (r < 0)
+ return r;
+
+ r = set_mempolicy(numa_policy_get_type(policy), nodes, maxnode);
+ if (r < 0)
+ return -errno;
+
+ return 0;
+}
+
+static const char* const mpol_table[] = {
+ [MPOL_DEFAULT] = "default",
+ [MPOL_PREFERRED] = "preferred",
+ [MPOL_BIND] = "bind",
+ [MPOL_INTERLEAVE] = "interleave",
+ [MPOL_LOCAL] = "local",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(mpol, int);
diff --git a/src/basic/cpu-set-util.h b/src/basic/cpu-set-util.h
index ec640b2ec9..295028cb54 100644
--- a/src/basic/cpu-set-util.h
+++ b/src/basic/cpu-set-util.h
@@ -8,6 +8,7 @@
#include <sched.h>
#include "macro.h"
+#include "missing.h"
/* This wraps the libc interface with a variable to keep the allocated size. */
typedef struct CPUSet {
@@ -52,3 +53,30 @@ int cpu_set_to_dbus(const CPUSet *set, uint8_t **ret, size_t *allocated);
int cpu_set_from_dbus(const uint8_t *bits, size_t size, CPUSet *set);
int cpus_in_affinity_mask(void);
+
+static inline bool mpol_is_valid(int t) {
+ return t >= MPOL_DEFAULT && t <= MPOL_LOCAL;
+}
+
+typedef struct NUMAPolicy {
+ /* Always use numa_policy_get_type() to read the value */
+ int type;
+ CPUSet nodes;
+} NUMAPolicy;
+
+bool numa_policy_is_valid(const NUMAPolicy *p);
+
+static inline int numa_policy_get_type(const NUMAPolicy *p) {
+ return p->type < 0 ? (p->nodes.set ? MPOL_PREFERRED : -1) : p->type;
+}
+
+static inline void numa_policy_reset(NUMAPolicy *p) {
+ assert(p);
+ cpu_set_reset(&p->nodes);
+ p->type = -1;
+}
+
+int apply_numa_policy(const NUMAPolicy *policy);
+
+const char* mpol_to_string(int i) _const_;
+int mpol_from_string(const char *s) _pure_;
diff --git a/src/basic/exit-status.c b/src/basic/exit-status.c
index 21af8c4c71..0a7a53b73d 100644
--- a/src/basic/exit-status.c
+++ b/src/basic/exit-status.c
@@ -155,6 +155,9 @@ const char* exit_status_to_string(int status, ExitStatusLevel level) {
case EXIT_CONFIGURATION_DIRECTORY:
return "CONFIGURATION_DIRECTORY";
+
+ case EXIT_NUMA_POLICY:
+ return "NUMA_POLICY";
}
}
diff --git a/src/basic/exit-status.h b/src/basic/exit-status.h
index c41e8b82c3..dc284aacb1 100644
--- a/src/basic/exit-status.h
+++ b/src/basic/exit-status.h
@@ -69,6 +69,7 @@ enum {
EXIT_CACHE_DIRECTORY,
EXIT_LOGS_DIRECTORY, /* 240 */
EXIT_CONFIGURATION_DIRECTORY,
+ EXIT_NUMA_POLICY,
};
typedef enum ExitStatusLevel {
diff --git a/src/basic/missing_syscall.h b/src/basic/missing_syscall.h
index 93c60458bf..014dd2b326 100644
--- a/src/basic/missing_syscall.h
+++ b/src/basic/missing_syscall.h
@@ -428,3 +428,46 @@ static inline ssize_t missing_statx(int dfd, const char *filename, unsigned flag
# define statx missing_statx
#endif
+
+#if !HAVE_SET_MEMPOLICY
+
+enum {
+ MPOL_DEFAULT,
+ MPOL_PREFERRED,
+ MPOL_BIND,
+ MPOL_INTERLEAVE,
+ MPOL_LOCAL,
+};
+
+static inline long missing_set_mempolicy(int mode, const unsigned long *nodemask,
+ unsigned long maxnode) {
+ long i;
+# ifdef __NR_set_mempolicy
+ i = syscall(__NR_set_mempolicy, mode, nodemask, maxnode);
+# else
+ errno = ENOSYS;
+ i = -1;
+# endif
+ return i;
+}
+
+# define set_mempolicy missing_set_mempolicy
+#endif
+
+
+#if !HAVE_GET_MEMPOLICY
+static inline long missing_get_mempolicy(int *mode, unsigned long *nodemask,
+ unsigned long maxnode, void *addr,
+ unsigned long flags) {
+ long i;
+# ifdef __NR_get_mempolicy
+ i = syscall(__NR_get_mempolicy, mode, nodemask, maxnode, addr, flags);
+# else
+ errno = ENOSYS;
+ i = -1;
+# endif
+ return i;
+}
+
+#define get_mempolicy missing_get_mempolicy
+#endif
diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
index 50ea71a281..198f149210 100644
--- a/src/core/dbus-execute.c
+++ b/src/core/dbus-execute.c
@@ -223,6 +223,48 @@ static int property_get_cpu_affinity(
return sd_bus_message_append_array(reply, 'y', c->cpu_set.set, c->cpu_set.allocated);
}
+static int property_get_numa_mask(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ ExecContext *c = userdata;
+ _cleanup_free_ uint8_t *array = NULL;
+ size_t allocated;
+
+ assert(bus);
+ assert(reply);
+ assert(c);
+
+ (void) cpu_set_to_dbus(&c->numa_policy.nodes, &array, &allocated);
+
+ return sd_bus_message_append_array(reply, 'y', array, allocated);
+}
+
+static int property_get_numa_policy(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+ ExecContext *c = userdata;
+ int32_t policy;
+
+ assert(bus);
+ assert(reply);
+ assert(c);
+
+ policy = numa_policy_get_type(&c->numa_policy);
+
+ return sd_bus_message_append_basic(reply, 'i', &policy);
+}
+
static int property_get_timer_slack_nsec(
sd_bus *bus,
const char *path,
@@ -698,6 +740,8 @@ const sd_bus_vtable bus_exec_vtable[] = {
SD_BUS_PROPERTY("CPUSchedulingPolicy", "i", property_get_cpu_sched_policy, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("CPUSchedulingPriority", "i", property_get_cpu_sched_priority, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("CPUAffinity", "ay", property_get_cpu_affinity, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("NUMAPolicy", "i", property_get_numa_policy, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("NUMAMask", "ay", property_get_numa_mask, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("TimerSlackNSec", "t", property_get_timer_slack_nsec, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("CPUSchedulingResetOnFork", "b", bus_property_get_bool, offsetof(ExecContext, cpu_sched_reset_on_fork), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("NonBlocking", "b", bus_property_get_bool, offsetof(ExecContext, non_blocking), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -1550,9 +1594,10 @@ int bus_exec_context_set_transient_property(
return 1;
}
#endif
- if (streq(name, "CPUAffinity")) {
+ if (STR_IN_SET(name, "CPUAffinity", "NUMAMask")) {
const void *a;
size_t n;
+ bool affinity = streq(name, "CPUAffinity");
_cleanup_(cpu_set_reset) CPUSet set = {};
r = sd_bus_message_read_array(message, 'y', &a, &n);
@@ -1565,7 +1610,7 @@ int bus_exec_context_set_transient_property(
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
if (n == 0) {
- cpu_set_reset(&c->cpu_set);
+ cpu_set_reset(affinity ? &c->cpu_set : &c->numa_policy.nodes);
unit_write_settingf(u, flags, name, "%s=", name);
} else {
_cleanup_free_ char *str = NULL;
@@ -1577,7 +1622,7 @@ int bus_exec_context_set_transient_property(
/* We forego any optimizations here, and always create the structure using
* cpu_set_add_all(), because we don't want to care if the existing size we
* got over dbus is appropriate. */
- r = cpu_set_add_all(&c->cpu_set, &set);
+ r = cpu_set_add_all(affinity ? &c->cpu_set : &c->numa_policy.nodes, &set);
if (r < 0)
return r;
@@ -1587,6 +1632,20 @@ int bus_exec_context_set_transient_property(
return 1;
+ } else if (streq(name, "NUMAPolicy")) {
+ int32_t type;
+
+ r = sd_bus_message_read(message, "i", &type);
+ if (r < 0)
+ return r;
+
+ if (!mpol_is_valid(type))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid NUMAPolicy value: %i", type);
+
+ if (!UNIT_WRITE_FLAGS_NOOP(flags))
+ c->numa_policy.type = type;
+
+ return 1;
} else if (streq(name, "IOSchedulingClass")) {
int32_t q;
diff --git a/src/core/execute.c b/src/core/execute.c
index bc26aa66e7..56aa89e1ec 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -2997,6 +2997,16 @@ static int exec_child(
return log_unit_error_errno(unit, errno, "Failed to set up CPU affinity: %m");
}
+ if (mpol_is_valid(numa_policy_get_type(&context->numa_policy))) {
+ r = apply_numa_policy(&context->numa_policy);
+ if (r == -EOPNOTSUPP)
+ log_unit_debug_errno(unit, r, "NUMA support not available, ignoring.");
+ else if (r < 0) {
+ *exit_status = EXIT_NUMA_POLICY;
+ return log_unit_error_errno(unit, r, "Failed to set NUMA memory policy: %m");
+ }
+ }
+
if (context->ioprio_set)
if (ioprio_set(IOPRIO_WHO_PROCESS, 0, context->ioprio) < 0) {
*exit_status = EXIT_IOPRIO;
@@ -3651,6 +3661,7 @@ void exec_context_init(ExecContext *c) {
assert_cc(NAMESPACE_FLAGS_INITIAL != NAMESPACE_FLAGS_ALL);
c->restrict_namespaces = NAMESPACE_FLAGS_INITIAL;
c->log_level_max = -1;
+ numa_policy_reset(&c->numa_policy);
}
void exec_context_done(ExecContext *c) {
@@ -3695,6 +3706,7 @@ void exec_context_done(ExecContext *c) {
c->n_temporary_filesystems = 0;
cpu_set_reset(&c->cpu_set);
+ numa_policy_reset(&c->numa_policy);
c->utmp_id = mfree(c->utmp_id);
c->selinux_context = mfree(c->selinux_context);
@@ -4104,6 +4116,14 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
fprintf(f, "%sCPUAffinity: %s\n", prefix, affinity);
}
+ if (mpol_is_valid(numa_policy_get_type(&c->numa_policy))) {
+ _cleanup_free_ char *nodes = NULL;
+
+ nodes = cpu_set_to_range_string(&c->numa_policy.nodes);
+ fprintf(f, "%sNUMAPolicy: %s\n", prefix, mpol_to_string(numa_policy_get_type(&c->numa_policy)));
+ fprintf(f, "%sNUMAMask: %s\n", prefix, strnull(nodes));
+ }
+
if (c->timer_slack_nsec != NSEC_INFINITY)
fprintf(f, "%sTimerSlackNSec: "NSEC_FMT "\n", prefix, c->timer_slack_nsec);
diff --git a/src/core/execute.h b/src/core/execute.h
index e1e7a494cd..b2eb55f8f5 100644
--- a/src/core/execute.h
+++ b/src/core/execute.h
@@ -150,6 +150,7 @@ struct ExecContext {
int cpu_sched_priority;
CPUSet cpu_set;
+ NUMAPolicy numa_policy;
ExecInput std_input;
ExecOutput std_output;
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
index 1066bcfb8f..cdf4d14c4e 100644
--- a/src/core/load-fragment-gperf.gperf.m4
+++ b/src/core/load-fragment-gperf.gperf.m4
@@ -36,6 +36,8 @@ $1.CPUSchedulingPolicy, config_parse_exec_cpu_sched_policy, 0,
$1.CPUSchedulingPriority, config_parse_exec_cpu_sched_prio, 0, offsetof($1, exec_context)
$1.CPUSchedulingResetOnFork, config_parse_bool, 0, offsetof($1, exec_context.cpu_sched_reset_on_fork)
$1.CPUAffinity, config_parse_exec_cpu_affinity, 0, offsetof($1, exec_context)
+$1.NUMAPolicy, config_parse_numa_policy, 0, offsetof($1, exec_context.numa_policy.type)
+$1.NUMAMask, config_parse_numa_mask, 0, offsetof($1, exec_context.numa_policy)
$1.UMask, config_parse_mode, 0, offsetof($1, exec_context.umask)
$1.Environment, config_parse_environ, 0, offsetof($1, exec_context.environment)
$1.EnvironmentFile, config_parse_unit_env_file, 0, offsetof($1, exec_context.environment_files)
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index 34ae834188..35dd595098 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -93,6 +93,7 @@ DEFINE_CONFIG_PARSE_PTR(config_parse_blockio_weight, cg_blkio_weight_parse, uint
DEFINE_CONFIG_PARSE_PTR(config_parse_cg_weight, cg_weight_parse, uint64_t, "Invalid weight");
DEFINE_CONFIG_PARSE_PTR(config_parse_cpu_shares, cg_cpu_shares_parse, uint64_t, "Invalid CPU shares");
DEFINE_CONFIG_PARSE_PTR(config_parse_exec_mount_flags, mount_propagation_flags_from_string, unsigned long, "Failed to parse mount flag");
+DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(config_parse_numa_policy, mpol, int, -1, "Invalid NUMA policy type");
int config_parse_unit_deps(
const char *unit,
@@ -1159,6 +1160,33 @@ int config_parse_exec_cpu_sched_policy(const char *unit,
return 0;
}
+int config_parse_numa_mask(const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+ int r;
+ NUMAPolicy *p = data;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = parse_cpu_set_extend(rvalue, &p->nodes, true, unit, filename, line, lvalue);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse NUMA node mask, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ return r;
+}
+
int config_parse_exec_cpu_sched_prio(const char *unit,
const char *filename,
unsigned line,
diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h
index dad281ef72..f2ca1b8ee7 100644
--- a/src/core/load-fragment.h
+++ b/src/core/load-fragment.h
@@ -102,6 +102,8 @@ CONFIG_PARSER_PROTOTYPE(config_parse_job_timeout_sec);
CONFIG_PARSER_PROTOTYPE(config_parse_job_running_timeout_sec);
CONFIG_PARSER_PROTOTYPE(config_parse_log_extra_fields);
CONFIG_PARSER_PROTOTYPE(config_parse_collect_mode);
+CONFIG_PARSER_PROTOTYPE(config_parse_numa_policy);
+CONFIG_PARSER_PROTOTYPE(config_parse_numa_mask);
/* gperf prototypes */
const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, GPERF_LEN_TYPE length);
diff --git a/src/core/main.c b/src/core/main.c
index c74dc641c1..83f9dd5878 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -134,6 +134,7 @@ static uint64_t arg_default_tasks_max;
static sd_id128_t arg_machine_id;
static EmergencyAction arg_cad_burst_action;
static CPUSet arg_cpu_affinity;
+static NUMAPolicy arg_numa_policy;
static int parse_configuration(void);
@@ -660,6 +661,8 @@ static int parse_config_file(void) {
{ "Manager", "ShowStatus", config_parse_show_status, 0, &arg_show_status },
{ "Manager", "CPUAffinity", config_parse_cpu_affinity2, 0, &arg_cpu_affinity },
{ "Manager", "JoinControllers", config_parse_join_controllers, 0, &arg_join_controllers },
+ { "Manager", "NUMAPolicy", config_parse_numa_policy, 0, &arg_numa_policy.type },
+ { "Manager", "NUMAMask", config_parse_numa_mask, 0, &arg_numa_policy },
{ "Manager", "RuntimeWatchdogSec", config_parse_sec, 0, &arg_runtime_watchdog },
{ "Manager", "ShutdownWatchdogSec", config_parse_sec, 0, &arg_shutdown_watchdog },
{ "Manager", "WatchdogDevice", config_parse_path, 0, &arg_watchdog_device },
@@ -1501,6 +1504,27 @@ static void update_cpu_affinity(bool skip_setup) {
log_warning_errno(errno, "Failed to set CPU affinity: %m");
}
+static void update_numa_policy(bool skip_setup) {
+ int r;
+ _cleanup_free_ char *nodes = NULL;
+ const char * policy = NULL;
+
+ if (skip_setup || !mpol_is_valid(numa_policy_get_type(&arg_numa_policy)))
+ return;
+
+ if (DEBUG_LOGGING) {
+ policy = mpol_to_string(numa_policy_get_type(&arg_numa_policy));
+ nodes = cpu_set_to_range_string(&arg_numa_policy.nodes);
+ log_debug("Setting NUMA policy to %s, with nodes %s.", strnull(policy), strnull(nodes));
+ }
+
+ r = apply_numa_policy(&arg_numa_policy);
+ if (r == -EOPNOTSUPP)
+ log_debug_errno(r, "NUMA support not available, ignoring.");
+ else if (r < 0)
+ log_warning_errno(r, "Failed to set NUMA memory policy: %m");
+}
+
static void do_reexecute(
int argc,
char *argv[],
@@ -1672,6 +1696,7 @@ static int invoke_main_loop(
set_manager_defaults(m);
update_cpu_affinity(false);
+ update_numa_policy(false);
if (saved_log_level >= 0)
manager_override_log_level(m, saved_log_level);
@@ -1832,6 +1857,7 @@ static int initialize_runtime(
return 0;
update_cpu_affinity(skip_setup);
+ update_numa_policy(skip_setup);
if (arg_system) {
/* Make sure we leave a core dump without panicing the kernel. */
@@ -2011,6 +2037,7 @@ static void reset_arguments(void) {
arg_cad_burst_action = EMERGENCY_ACTION_REBOOT_FORCE;
cpu_set_reset(&arg_cpu_affinity);
+ numa_policy_reset(&arg_numa_policy);
}
static int parse_configuration(void) {
diff --git a/src/core/system.conf.in b/src/core/system.conf.in
index 653ec6b8c9..0d93fbf147 100644
--- a/src/core/system.conf.in
+++ b/src/core/system.conf.in
@@ -24,6 +24,8 @@
#CtrlAltDelBurstAction=reboot-force
#CPUAffinity=1 2
#JoinControllers=cpu,cpuacct net_cls,net_prio
+#NUMAPolicy=default
+#NUMAMask=
#RuntimeWatchdogSec=0
#ShutdownWatchdogSec=10min
#CapabilityBoundingSet=
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
index ec8732c226..055edd6e22 100644
--- a/src/shared/bus-unit-util.c
+++ b/src/shared/bus-unit-util.c
@@ -947,6 +947,34 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
return bus_append_byte_array(m, field, array, allocated);
}
+ if (streq(field, "NUMAPolicy")) {
+ r = mpol_from_string(eq);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
+
+ r = sd_bus_message_append(m, "(sv)", field, "i", (int32_t) r);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return 1;
+ }
+
+ if (streq(field, "NUMAMask")) {
+ _cleanup_(cpu_set_reset) CPUSet nodes = {};
+ _cleanup_free_ uint8_t *array = NULL;
+ size_t allocated;
+
+ r = parse_cpu_set(eq, &nodes);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
+
+ r = cpu_set_to_dbus(&nodes, &array, &allocated);
+ if (r < 0)
+ return log_error_errno(r, "Failed to serialize NUMAMask: %m");
+
+ return bus_append_byte_array(m, field, array, allocated);
+ }
+
if (STR_IN_SET(field, "RestrictAddressFamilies", "SystemCallFilter")) {
int whitelist = 1;
const char *p = eq;
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 0154b300a3..7274921e6d 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -4573,6 +4573,20 @@ static int print_property(const char *name, sd_bus_message *m, bool value, bool
switch (bus_type) {
+ case SD_BUS_TYPE_INT32:
+ if (streq(name, "NUMAPolicy")) {
+ int32_t i;
+
+ r = sd_bus_message_read_basic(m, bus_type, &i);
+ if (r < 0)
+ return r;
+
+ print_prop(name, "%s", strna(mpol_to_string(i)));
+
+ return 1;
+ }
+ break;
+
case SD_BUS_TYPE_STRUCT:
if (contents[0] == SD_BUS_TYPE_UINT32 && streq(name, "Job")) {
@@ -4878,7 +4892,7 @@ static int print_property(const char *name, sd_bus_message *m, bool value, bool
print_prop(name, "%s", h);
return 1;
- } else if (contents[0] == SD_BUS_TYPE_BYTE && streq(name, "CPUAffinity")) {
+ } else if (contents[0] == SD_BUS_TYPE_BYTE && STR_IN_SET(name, "CPUAffinity", "NUMAMask")) {
_cleanup_free_ char *affinity = NULL;
_cleanup_(cpu_set_reset) CPUSet set = {};
const void *a;
@@ -4890,7 +4904,7 @@ static int print_property(const char *name, sd_bus_message *m, bool value, bool
r = cpu_set_from_dbus(a, n, &set);
if (r < 0)
- return log_error_errno(r, "Failed to deserialize CPUAffinity: %m");
+ return log_error_errno(r, "Failed to deserialize %s: %m", name);
affinity = cpu_set_to_range_string(&set);
if (!affinity)

View File

@ -0,0 +1,25 @@
From b47f26558e5234ec8cf2ecc3674c94a87f20ec69 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michal=20Sekleta=CC=81r?= <msekleta@redhat.com>
Date: Thu, 28 Nov 2019 15:47:43 +0100
Subject: [PATCH] core: disable CPUAccounting by default
Related: #1734787
[RHEL-only]
---
src/core/main.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/core/main.c b/src/core/main.c
index 83f9dd5878..c83249a8dc 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -2026,7 +2026,7 @@ static void reset_arguments(void) {
/* arg_serialization — ignore */
- arg_default_cpu_accounting = -1;
+ arg_default_cpu_accounting = 0;
arg_default_io_accounting = false;
arg_default_ip_accounting = false;
arg_default_blockio_accounting = false;

View File

@ -0,0 +1,24 @@
From cf1a9df1171273fc1ed3f977b5ec52aba27674bf Mon Sep 17 00:00:00 2001
From: David Tardon <dtardon@redhat.com>
Date: Tue, 3 Dec 2019 14:04:00 +0100
Subject: [PATCH] set kptr_restrict=1
Resolves: #1689346
---
sysctl.d/50-default.conf | 3 +++
1 file changed, 3 insertions(+)
diff --git a/sysctl.d/50-default.conf b/sysctl.d/50-default.conf
index e263cf0628..e0afc9c702 100644
--- a/sysctl.d/50-default.conf
+++ b/sysctl.d/50-default.conf
@@ -21,6 +21,9 @@ kernel.sysrq = 16
# Append the PID to the core filename
kernel.core_uses_pid = 1
+# https://bugzilla.redhat.com/show_bug.cgi?id=1689346
+kernel.kptr_restrict = 1
+
# Source route verification
net.ipv4.conf.all.rp_filter = 1

View File

@ -0,0 +1,34 @@
From 40612e4e7690c613cba7ac87b9d782724e623a39 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michal=20Sekleta=CC=81r?= <msekleta@redhat.com>
Date: Wed, 27 Nov 2019 14:27:58 +0100
Subject: [PATCH] cryptsetup: reduce the chance that we will be OOM killed
cryptsetup introduced optional locking scheme that should serialize
unlocking keyslots which use memory hard key derivation
function (argon2). Using the serialization should prevent OOM situation
in early boot while unlocking encrypted volumes.
(cherry picked from commit 408c81f62454684dfbff1c95ce3210d06f256e58)
Resolves: #1696602
---
src/cryptsetup/cryptsetup.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c
index 4e1b3eff19..9071126c2e 100644
--- a/src/cryptsetup/cryptsetup.c
+++ b/src/cryptsetup/cryptsetup.c
@@ -656,6 +656,12 @@ int main(int argc, char *argv[]) {
if (arg_discards)
flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS;
+#ifdef CRYPT_ACTIVATE_SERIALIZE_MEMORY_HARD_PBKDF
+ /* Try to decrease the risk of OOM event if memory hard key derivation function is in use */
+ /* https://gitlab.com/cryptsetup/cryptsetup/issues/446/ */
+ flags |= CRYPT_ACTIVATE_SERIALIZE_MEMORY_HARD_PBKDF;
+#endif
+
if (arg_timeout == USEC_INFINITY)
until = 0;
else

View File

@ -0,0 +1,136 @@
From cb084637ba1c8558f1538ce300c5520a6764dc76 Mon Sep 17 00:00:00 2001
From: HATAYAMA Daisuke <d.hatayama@jp.fujitsu.com>
Date: Mon, 28 Oct 2019 19:35:24 +0900
Subject: [PATCH] core, job: fix breakage of ordering dependencies by systemctl
reload command
Currently, systemctl reload command breaks ordering dependencies if it's
executed when its target service unit is in activating state.
For example, prepare A.service, B.service and C.target as follows:
# systemctl cat A.service B.service C.target
# /etc/systemd/system/A.service
[Unit]
Description=A
[Service]
Type=oneshot
ExecStart=/usr/bin/echo A1
ExecStart=/usr/bin/sleep 60
ExecStart=/usr/bin/echo A2
ExecReload=/usr/bin/echo A reloaded
RemainAfterExit=yes
# /etc/systemd/system/B.service
[Unit]
Description=B
After=A.service
[Service]
Type=oneshot
ExecStart=/usr/bin/echo B
RemainAfterExit=yes
# /etc/systemd/system/C.target
[Unit]
Description=C
Wants=A.service B.service
Start them.
# systemctl daemon-reload
# systemctl start C.target
Then, we have:
# LANG=C journalctl --no-pager -u A.service -u B.service -u C.target -b
-- Logs begin at Mon 2019-09-09 00:25:06 EDT, end at Thu 2019-10-24 22:28:47 EDT. --
Oct 24 22:27:47 localhost.localdomain systemd[1]: Starting A...
Oct 24 22:27:47 localhost.localdomain systemd[1]: A.service: Child 967 belongs to A.service.
Oct 24 22:27:47 localhost.localdomain systemd[1]: A.service: Main process exited, code=exited, status=0/SUCCESS
Oct 24 22:27:47 localhost.localdomain systemd[1]: A.service: Running next main command for state start.
Oct 24 22:27:47 localhost.localdomain systemd[1]: A.service: Passing 0 fds to service
Oct 24 22:27:47 localhost.localdomain systemd[1]: A.service: About to execute: /usr/bin/sleep 60
Oct 24 22:27:47 localhost.localdomain systemd[1]: A.service: Forked /usr/bin/sleep as 968
Oct 24 22:27:47 localhost.localdomain systemd[968]: A.service: Executing: /usr/bin/sleep 60
Oct 24 22:27:52 localhost.localdomain systemd[1]: A.service: Trying to enqueue job A.service/reload/replace
Oct 24 22:27:52 localhost.localdomain systemd[1]: A.service: Merged into running job, re-running: A.service/reload as 1288
Oct 24 22:27:52 localhost.localdomain systemd[1]: A.service: Enqueued job A.service/reload as 1288
Oct 24 22:27:52 localhost.localdomain systemd[1]: A.service: Unit cannot be reloaded because it is inactive.
Oct 24 22:27:52 localhost.localdomain systemd[1]: A.service: Job 1288 A.service/reload finished, result=invalid
Oct 24 22:27:52 localhost.localdomain systemd[1]: B.service: Passing 0 fds to service
Oct 24 22:27:52 localhost.localdomain systemd[1]: B.service: About to execute: /usr/bin/echo B
Oct 24 22:27:52 localhost.localdomain systemd[1]: B.service: Forked /usr/bin/echo as 970
Oct 24 22:27:52 localhost.localdomain systemd[970]: B.service: Executing: /usr/bin/echo B
Oct 24 22:27:52 localhost.localdomain systemd[1]: B.service: Failed to send unit change signal for B.service: Connection reset by peer
Oct 24 22:27:52 localhost.localdomain systemd[1]: B.service: Changed dead -> start
Oct 24 22:27:52 localhost.localdomain systemd[1]: Starting B...
Oct 24 22:27:52 localhost.localdomain echo[970]: B
Oct 24 22:27:52 localhost.localdomain systemd[1]: B.service: Child 970 belongs to B.service.
Oct 24 22:27:52 localhost.localdomain systemd[1]: B.service: Main process exited, code=exited, status=0/SUCCESS
Oct 24 22:27:52 localhost.localdomain systemd[1]: B.service: Changed start -> exited
Oct 24 22:27:52 localhost.localdomain systemd[1]: B.service: Job 1371 B.service/start finished, result=done
Oct 24 22:27:52 localhost.localdomain systemd[1]: Started B.
Oct 24 22:27:52 localhost.localdomain systemd[1]: C.target: Job 1287 C.target/start finished, result=done
Oct 24 22:27:52 localhost.localdomain systemd[1]: Reached target C.
Oct 24 22:27:52 localhost.localdomain systemd[1]: C.target: Failed to send unit change signal for C.target: Connection reset by peer
Oct 24 22:28:47 localhost.localdomain systemd[1]: A.service: Child 968 belongs to A.service.
Oct 24 22:28:47 localhost.localdomain systemd[1]: A.service: Main process exited, code=exited, status=0/SUCCESS
Oct 24 22:28:47 localhost.localdomain systemd[1]: A.service: Running next main command for state start.
Oct 24 22:28:47 localhost.localdomain systemd[1]: A.service: Passing 0 fds to service
Oct 24 22:28:47 localhost.localdomain systemd[1]: A.service: About to execute: /usr/bin/echo A2
Oct 24 22:28:47 localhost.localdomain systemd[1]: A.service: Forked /usr/bin/echo as 972
Oct 24 22:28:47 localhost.localdomain systemd[972]: A.service: Executing: /usr/bin/echo A2
Oct 24 22:28:47 localhost.localdomain echo[972]: A2
Oct 24 22:28:47 localhost.localdomain systemd[1]: A.service: Child 972 belongs to A.service.
Oct 24 22:28:47 localhost.localdomain systemd[1]: A.service: Main process exited, code=exited, status=0/SUCCESS
Oct 24 22:28:47 localhost.localdomain systemd[1]: A.service: Changed start -> exited
The issue occurs not only in reload command, i.e.:
- reload
- try-restart
- reload-or-restart
- reload-or-try-restart commands
The cause of this issue is that job_type_collapse() doesn't take care of the
activating state.
Fixes: #10464
(cherry picked from commit d1559793df555212271e490a4a72f55826caf5b4)
Resolves: #1766417
---
src/core/job.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/core/job.c b/src/core/job.c
index 8552ffb704..769ed6d603 100644
--- a/src/core/job.c
+++ b/src/core/job.c
@@ -403,21 +403,21 @@ JobType job_type_collapse(JobType t, Unit *u) {
case JOB_TRY_RESTART:
s = unit_active_state(u);
- if (UNIT_IS_INACTIVE_OR_DEACTIVATING(s))
+ if (!UNIT_IS_ACTIVE_OR_RELOADING(s))
return JOB_NOP;
return JOB_RESTART;
case JOB_TRY_RELOAD:
s = unit_active_state(u);
- if (UNIT_IS_INACTIVE_OR_DEACTIVATING(s))
+ if (!UNIT_IS_ACTIVE_OR_RELOADING(s))
return JOB_NOP;
return JOB_RELOAD;
case JOB_RELOAD_OR_START:
s = unit_active_state(u);
- if (UNIT_IS_INACTIVE_OR_DEACTIVATING(s))
+ if (!UNIT_IS_ACTIVE_OR_RELOADING(s))
return JOB_START;
return JOB_RELOAD;

View File

@ -0,0 +1,149 @@
From 613a02b7d67864af1860e9137e2ee101d603463e Mon Sep 17 00:00:00 2001
From: Jan Synacek <jsynacek@redhat.com>
Date: Thu, 25 Apr 2019 12:19:16 +0200
Subject: [PATCH] debug-generator: enable custom systemd.debug_shell tty
(cherry picked from commit 93912e872fb14e9c372e090409e429084a6450f5)
Resolves: #1723722
---
man/custom-entities.ent.in | 1 +
man/systemd-debug-generator.xml | 13 ++++++---
meson.build | 1 +
src/debug-generator/debug-generator.c | 41 +++++++++++++++++++++------
4 files changed, 43 insertions(+), 13 deletions(-)
diff --git a/man/custom-entities.ent.in b/man/custom-entities.ent.in
index e2bd44e5e7..85805777a0 100644
--- a/man/custom-entities.ent.in
+++ b/man/custom-entities.ent.in
@@ -8,3 +8,4 @@
<!ENTITY CERTIFICATE_ROOT @CERTIFICATE_ROOT@>
<!ENTITY MEMORY_ACCOUNTING_DEFAULT @MEMORY_ACCOUNTING_DEFAULT_YES_NO@>
<!ENTITY KILL_USER_PROCESSES @KILL_USER_PROCESSES_YES_NO@>
+<!ENTITY DEBUGTTY @DEBUGTTY@>
diff --git a/man/systemd-debug-generator.xml b/man/systemd-debug-generator.xml
index fa88e8ac01..25d8b1a873 100644
--- a/man/systemd-debug-generator.xml
+++ b/man/systemd-debug-generator.xml
@@ -1,6 +1,10 @@
<?xml version="1.0"?>
<!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
SPDX-License-Identifier: LGPL-2.1+
-->
@@ -57,9 +61,10 @@
<option>rd.systemd.debug_shell</option> option is
specified, the debug shell service
<literal>debug-shell.service</literal> is pulled into the boot
- transaction. It will spawn a debug shell on tty9 during early
- system startup. Note that the shell may also be turned on
- persistently by enabling it with
+ transaction and a debug shell will be spawned during early boot.
+ By default, <filename>&DEBUGTTY;</filename> is used, but a specific tty can also be set,
+ either with or without the <filename>/dev/</filename> prefix.
+ Note that the shell may also be turned on persistently by enabling it with
<citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>'s
<command>enable</command> command.
<option>rd.systemd.debug_shell=</option> is honored only by initial
diff --git a/meson.build b/meson.build
index fe82ca4ac2..70811c29cf 100644
--- a/meson.build
+++ b/meson.build
@@ -768,6 +768,7 @@ conf.set_quoted('GETTEXT_PACKAGE', meson.project_name())
substs.set('SUSHELL', get_option('debug-shell'))
substs.set('DEBUGTTY', get_option('debug-tty'))
+conf.set_quoted('DEBUGTTY', get_option('debug-tty'))
enable_debug_hashmap = false
enable_debug_mmap_cache = false
diff --git a/src/debug-generator/debug-generator.c b/src/debug-generator/debug-generator.c
index 800d31cebe..ddef385833 100644
--- a/src/debug-generator/debug-generator.c
+++ b/src/debug-generator/debug-generator.c
@@ -1,8 +1,11 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#include "alloc-util.h"
+#include "dropin.h"
+#include "generator.h"
#include "mkdir.h"
#include "parse-util.h"
+#include "path-util.h"
#include "proc-cmdline.h"
#include "special.h"
#include "string-util.h"
@@ -14,7 +17,7 @@ static char *arg_default_unit = NULL;
static const char *arg_dest = "/tmp";
static char **arg_mask = NULL;
static char **arg_wants = NULL;
-static bool arg_debug_shell = false;
+static char *arg_debug_shell = NULL;
static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
int r;
@@ -50,15 +53,16 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
return log_oom();
} else if (proc_cmdline_key_streq(key, "systemd.debug_shell")) {
+ const char *t = NULL;
- if (value) {
- r = parse_boolean(value);
- if (r < 0)
- log_error("Failed to parse systemd.debug_shell= argument '%s', ignoring.", value);
- else
- arg_debug_shell = r;
- } else
- arg_debug_shell = true;
+ r = value ? parse_boolean(value) : 1;
+ if (r < 0)
+ t = skip_dev_prefix(value);
+ else if (r > 0)
+ t = skip_dev_prefix(DEBUGTTY);
+
+ if (free_and_strdup(&arg_debug_shell, t) < 0)
+ return log_oom();
} else if (streq(key, "systemd.unit")) {
@@ -136,6 +140,23 @@ static int generate_wants_symlinks(void) {
return r;
}
+static void install_debug_shell_dropin(const char *dir) {
+ int r;
+
+ if (streq(arg_debug_shell, skip_dev_prefix(DEBUGTTY)))
+ return;
+
+ r = write_drop_in_format(dir, "debug-shell.service", 50, "tty",
+ "[Unit]\n"
+ "Description=Early root shell on /dev/%s FOR DEBUGGING ONLY\n"
+ "ConditionPathExists=\n"
+ "[Service]\n"
+ "TTYPath=/dev/%s",
+ arg_debug_shell, arg_debug_shell);
+ if (r < 0)
+ log_warning_errno(r, "Failed to write drop-in for debug-shell.service, ignoring: %m");
+}
+
int main(int argc, char *argv[]) {
int r, q;
@@ -164,6 +185,8 @@ int main(int argc, char *argv[]) {
r = log_oom();
goto finish;
}
+
+ install_debug_shell_dropin(arg_dest);
}
r = generate_mask_symlinks();

View File

@ -0,0 +1,118 @@
From f4344bb4055cab8dc3bbe82a7f3d97fc6fabcb7e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Tue, 4 Jun 2019 09:19:04 +0200
Subject: [PATCH] test-cpu-set-util: fix comparison for allocation size
On i386, __cpu_mask is 4 bytes, so we'd check if c.allocated >= 0, and
gcc would warn about a bogus comparison. Let's round up.
Fixes #12726.
(cherry picked from commit a299ce058b41b21c87f36e77e2c563b0ddd1be0d)
Related: #1734787
---
src/test/test-cpu-set-util.c | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/src/test/test-cpu-set-util.c b/src/test/test-cpu-set-util.c
index 9522582891..3456add989 100644
--- a/src/test/test-cpu-set-util.c
+++ b/src/test/test-cpu-set-util.c
@@ -17,7 +17,7 @@ static void test_parse_cpu_set(void) {
/* Single value */
assert_se(parse_cpu_set_full("0", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
assert_se(c.set);
- assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
+ assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8));
assert_se(CPU_ISSET_S(0, c.allocated, c.set));
assert_se(CPU_COUNT_S(c.allocated, c.set) == 1);
@@ -33,7 +33,7 @@ static void test_parse_cpu_set(void) {
/* Simple range (from CPUAffinity example) */
assert_se(parse_cpu_set_full("1 2 4", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
assert_se(c.set);
- assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
+ assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8));
assert_se(CPU_ISSET_S(1, c.allocated, c.set));
assert_se(CPU_ISSET_S(2, c.allocated, c.set));
assert_se(CPU_ISSET_S(4, c.allocated, c.set));
@@ -50,7 +50,7 @@ static void test_parse_cpu_set(void) {
/* A more interesting range */
assert_se(parse_cpu_set_full("0 1 2 3 8 9 10 11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
- assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
+ assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8));
assert_se(CPU_COUNT_S(c.allocated, c.set) == 8);
for (cpu = 0; cpu < 4; cpu++)
assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
@@ -68,7 +68,7 @@ static void test_parse_cpu_set(void) {
/* Quoted strings */
assert_se(parse_cpu_set_full("8 '9' 10 \"11\"", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
- assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
+ assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8));
assert_se(CPU_COUNT_S(c.allocated, c.set) == 4);
for (cpu = 8; cpu < 12; cpu++)
assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
@@ -83,7 +83,7 @@ static void test_parse_cpu_set(void) {
/* Use commas as separators */
assert_se(parse_cpu_set_full("0,1,2,3 8,9,10,11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
- assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
+ assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8));
assert_se(CPU_COUNT_S(c.allocated, c.set) == 8);
for (cpu = 0; cpu < 4; cpu++)
assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
@@ -96,7 +96,7 @@ static void test_parse_cpu_set(void) {
/* Commas with spaces (and trailing comma, space) */
assert_se(parse_cpu_set_full("0, 1, 2, 3, 4, 5, 6, 7, 63, ", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
- assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
+ assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8));
assert_se(CPU_COUNT_S(c.allocated, c.set) == 9);
for (cpu = 0; cpu < 8; cpu++)
assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
@@ -113,7 +113,7 @@ static void test_parse_cpu_set(void) {
/* Ranges */
assert_se(parse_cpu_set_full("0-3,8-11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
- assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
+ assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8));
assert_se(CPU_COUNT_S(c.allocated, c.set) == 8);
for (cpu = 0; cpu < 4; cpu++)
assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
@@ -126,7 +126,7 @@ static void test_parse_cpu_set(void) {
/* Ranges with trailing comma, space */
assert_se(parse_cpu_set_full("0-3 8-11, ", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
- assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
+ assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8));
assert_se(CPU_COUNT_S(c.allocated, c.set) == 8);
for (cpu = 0; cpu < 4; cpu++)
assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
@@ -143,13 +143,13 @@ static void test_parse_cpu_set(void) {
/* Negative range (returns empty cpu_set) */
assert_se(parse_cpu_set_full("3-0", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
- assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
+ assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8));
assert_se(CPU_COUNT_S(c.allocated, c.set) == 0);
cpu_set_reset(&c);
/* Overlapping ranges */
assert_se(parse_cpu_set_full("0-7 4-11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
- assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
+ assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8));
assert_se(CPU_COUNT_S(c.allocated, c.set) == 12);
for (cpu = 0; cpu < 12; cpu++)
assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
@@ -164,7 +164,7 @@ static void test_parse_cpu_set(void) {
/* Mix ranges and individual CPUs */
assert_se(parse_cpu_set_full("0,2 4-11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
- assert_se(c.allocated >= sizeof(__cpu_mask) / 8);
+ assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8));
assert_se(CPU_COUNT_S(c.allocated, c.set) == 10);
assert_se(CPU_ISSET_S(0, c.allocated, c.set));
assert_se(CPU_ISSET_S(2, c.allocated, c.set));

View File

@ -0,0 +1,30 @@
From 3cf9361996b796eae0bda12aec8c92ddae1d5d48 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Tue, 4 Jun 2019 09:40:38 +0200
Subject: [PATCH] test-cpu-set-util: fix allocation size check on i386
We get just 28 bytes not 32 as on 64-bit architectures (__cpu_set_t is 4 bytes,
we need at least 26, so 28 satisfies the constraints).
(cherry picked from commit 64412970ac0d4b6f5c4bbd8816edc9bff9eab2de)
Related: #1734787
---
src/test/test-cpu-set-util.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/test/test-cpu-set-util.c b/src/test/test-cpu-set-util.c
index 3456add989..136eaca82d 100644
--- a/src/test/test-cpu-set-util.c
+++ b/src/test/test-cpu-set-util.c
@@ -256,7 +256,9 @@ static void test_cpu_set_to_from_dbus(void) {
assert_se(array);
assert_se(allocated == c.allocated);
- assert(memcmp(array, expected, sizeof expected) == 0);
+ assert_se(allocated <= sizeof expected);
+ assert_se(allocated >= DIV_ROUND_UP(201u, 8u)); /* We need at least 201 bits for our mask */
+ assert(memcmp(array, expected, allocated) == 0);
assert_se(cpu_set_from_dbus(array, allocated, &c2) == 0);
assert_se(c2.set);

View File

@ -13,7 +13,7 @@
Name: systemd
Url: http://www.freedesktop.org/wiki/Software/systemd
Version: 239
Release: 15%{?dist}
Release: 21%{?dist}
# For a breakdown of the licensing, see README
License: LGPLv2+ and MIT and GPLv2+
Summary: System and Service Manager
@ -250,6 +250,101 @@ Patch0197: 0197-test-add-test-for-Type-exec.patch
Patch0198: 0198-journal-gateway-explicitly-declare-local-variables.patch
Patch0199: 0199-tools-drop-unused-variable.patch
Patch0200: 0200-journal-gateway-use-localStorage-cursor-only-when-it.patch
Patch0201: 0201-sd-bus-deal-with-cookie-overruns.patch
Patch0202: 0202-journal-remote-do-not-request-Content-Length-if-Tran.patch
Patch0203: 0203-journal-do-not-remove-multiple-spaces-after-identifi.patch
Patch0204: 0204-cryptsetup-Do-not-fallback-to-PLAIN-mapping-if-LUKS-.patch
Patch0205: 0205-cryptsetup-call-crypt_load-for-LUKS-only-once.patch
Patch0206: 0206-cryptsetup-Add-LUKS2-token-support.patch
Patch0207: 0207-udev-scsi_id-fix-incorrect-page-length-when-get-devi.patch
Patch0208: 0208-Change-job-mode-of-manager-triggered-restarts-to-JOB.patch
Patch0209: 0209-bash-completion-analyze-support-security.patch
Patch0210: 0210-man-note-that-journal-does-not-validate-syslog-field.patch
Patch0211: 0211-rules-skip-memory-hotplug-on-ppc64.patch
Patch0212: 0212-mount-simplify-proc-self-mountinfo-handler.patch
Patch0213: 0213-mount-rescan-proc-self-mountinfo-before-processing-w.patch
Patch0214: 0214-swap-scan-proc-swaps-before-processing-waitid-result.patch
Patch0215: 0215-analyze-security-fix-potential-division-by-zero.patch
Patch0216: 0216-core-never-propagate-reload-failure-to-service-resul.patch
Patch0217: 0217-man-document-systemd-analyze-security.patch
Patch0218: 0218-man-reorder-and-add-examples-to-systemd-analyze-1.patch
Patch0219: 0219-travis-move-to-CentOS-8-docker-images.patch
Patch0220: 0220-travis-drop-SCL-remains.patch
Patch0221: 0221-syslog-fix-segfault-in-syslog_parse_priority.patch
Patch0222: 0222-sd-bus-make-strict-asan-shut-up.patch
Patch0223: 0223-travis-don-t-run-slow-tests-under-ASan-UBSan.patch
Patch0224: 0224-kernel-install-do-not-require-non-empty-kernel-cmdli.patch
Patch0225: 0225-ask-password-prevent-buffer-overrow-when-reading-fro.patch
Patch0226: 0226-core-try-to-reopen-dev-kmsg-again-right-after-mounti.patch
Patch0227: 0227-buildsys-don-t-garbage-collect-sections-while-linkin.patch
Patch0228: 0228-udev-introduce-CONST-key-name.patch
Patch0229: 0229-Call-getgroups-to-know-size-of-supplementary-groups-.patch
Patch0230: 0230-Consider-smb3-as-remote-filesystem.patch
Patch0231: 0231-process-util-introduce-pid_is_my_child-helper.patch
Patch0232: 0232-core-reduce-the-number-of-stalled-PIDs-from-the-watc.patch
Patch0233: 0233-core-only-watch-processes-when-it-s-really-necessary.patch
Patch0234: 0234-core-implement-per-unit-journal-rate-limiting.patch
Patch0235: 0235-path-stop-watching-path-specs-once-we-triggered-the-.patch
Patch0236: 0236-journald-fixed-assertion-failure-when-system-journal.patch
Patch0237: 0237-test-use-PBKDF2-instead-of-Argon2-in-cryptsetup.patch
Patch0238: 0238-test-mask-several-unnecessary-services.patch
Patch0239: 0239-test-bump-the-second-partition-s-size-to-50M.patch
Patch0240: 0240-shared-sleep-config-exclude-zram-devices-from-hibern.patch
Patch0241: 0241-selinux-don-t-log-SELINUX_INFO-and-SELINUX_WARNING-m.patch
Patch0242: 0242-sd-device-introduce-log_device_-macros.patch
Patch0243: 0243-udev-Add-id-program-and-rule-for-FIDO-security-token.patch
Patch0244: 0244-shared-but-util-drop-trusted-annotation-from-bus_ope.patch
Patch0245: 0245-sd-bus-adjust-indentation-of-comments.patch
Patch0246: 0246-resolved-do-not-run-loop-twice.patch
Patch0247: 0247-resolved-allow-access-to-Set-Link-and-Revert-methods.patch
Patch0248: 0248-resolved-query-polkit-only-after-parsing-the-data.patch
Patch0249: 0249-journal-rely-on-_cleanup_free_-to-free-a-temporary-s.patch
Patch0250: 0250-basic-user-util-allow-dots-in-user-names.patch
Patch0251: 0251-sd-bus-bump-message-queue-size-again.patch
Patch0252: 0252-tests-put-fuzz_journald_processing_function-in-a-.c-.patch
Patch0253: 0253-tests-add-a-fuzzer-for-dev_kmsg_record.patch
Patch0254: 0254-basic-remove-an-assertion-from-cunescape_one.patch
Patch0255: 0255-journal-fix-an-off-by-one-error-in-dev_kmsg_record.patch
Patch0256: 0256-tests-add-a-reproducer-for-a-memory-leak-fixed-in-30.patch
Patch0257: 0257-tests-add-a-reproducer-for-a-heap-buffer-overflow-fi.patch
Patch0258: 0258-test-initialize-syslog_fd-in-fuzz-journald-kmsg-too.patch
Patch0259: 0259-tests-add-a-fuzzer-for-process_audit_string.patch
Patch0260: 0260-journald-check-whether-sscanf-has-changed-the-value-.patch
Patch0261: 0261-tests-introduce-dummy_server_init-and-use-it-in-all-.patch
Patch0262: 0262-tests-add-a-fuzzer-for-journald-streams.patch
Patch0263: 0263-tests-add-a-fuzzer-for-server_process_native_file.patch
Patch0264: 0264-fuzz-journal-stream-avoid-assertion-failure-on-sampl.patch
Patch0265: 0265-journald-take-leading-spaces-into-account-in-syslog_.patch
Patch0266: 0266-Add-a-warning-about-the-difference-in-permissions-be.patch
Patch0267: 0267-execute-remove-one-redundant-comparison-check.patch
Patch0268: 0268-core-change-ownership-mode-of-the-execution-director.patch
Patch0269: 0269-core-dbus-execute-remove-unnecessary-initialization.patch
Patch0270: 0270-shared-cpu-set-util-move-the-part-to-print-cpu-set-i.patch
Patch0271: 0271-shared-cpu-set-util-remove-now-unused-CPU_SIZE_TO_NU.patch
Patch0272: 0272-Rework-cpu-affinity-parsing.patch
Patch0273: 0273-Move-cpus_in_affinity_mask-to-cpu-set-util.-ch.patch
Patch0274: 0274-test-cpu-set-util-add-simple-test-for-cpus_in_affini.patch
Patch0275: 0275-test-cpu-set-util-add-a-smoke-test-for-test_parse_cp.patch
Patch0276: 0276-pid1-parse-CPUAffinity-in-incremental-fashion.patch
Patch0277: 0277-pid1-don-t-reset-setting-from-proc-cmdline-upon-rest.patch
Patch0278: 0278-pid1-when-reloading-configuration-forget-old-setting.patch
Patch0279: 0279-test-execute-use-CPUSet-too.patch
Patch0280: 0280-shared-cpu-set-util-drop-now-unused-cleanup-function.patch
Patch0281: 0281-shared-cpu-set-util-make-transfer-of-cpu_set_t-over-.patch
Patch0282: 0282-test-cpu-set-util-add-test-for-dbus-conversions.patch
Patch0283: 0283-shared-cpu-set-util-introduce-cpu_set_to_range.patch
Patch0284: 0284-systemctl-present-CPUAffinity-mask-as-a-list-of-CPU-.patch
Patch0285: 0285-shared-cpu-set-util-only-force-range-printing-one-ti.patch
Patch0286: 0286-execute-dump-CPUAffinity-as-a-range-string-instead-o.patch
Patch0287: 0287-cpu-set-util-use-d-d-format-in-cpu_set_to_range_stri.patch
Patch0288: 0288-core-introduce-NUMAPolicy-and-NUMAMask-options.patch
Patch0289: 0289-core-disable-CPUAccounting-by-default.patch
Patch0290: 0290-set-kptr_restrict-1.patch
Patch0291: 0291-cryptsetup-reduce-the-chance-that-we-will-be-OOM-kil.patch
Patch0292: 0292-core-job-fix-breakage-of-ordering-dependencies-by-sy.patch
Patch0293: 0293-debug-generator-enable-custom-systemd.debug_shell-tt.patch
Patch0294: 0294-test-cpu-set-util-fix-comparison-for-allocation-size.patch
Patch0295: 0295-test-cpu-set-util-fix-allocation-size-check-on-i386.patch
%ifarch %{ix86} x86_64 aarch64
@ -869,6 +964,120 @@ fi
%files tests -f .file-list-tests
%changelog
* Mon Dec 09 2019 systemd maintenance team <systemd-maint@redhat.com> - 239-21
- test-cpu-set-util: fix comparison for allocation size (#1734787)
- test-cpu-set-util: fix allocation size check on i386 (#1734787)
* Mon Dec 09 2019 systemd maintenance team <systemd-maint@redhat.com> - 239-20
- journal: rely on _cleanup_free_ to free a temporary string used in client_context_read_cgroup (#1764560)
- basic/user-util: allow dots in user names (#1717603)
- sd-bus: bump message queue size again (#1770189)
- tests: put fuzz_journald_processing_function in a .c file (#1764560)
- tests: add a fuzzer for dev_kmsg_record (#1764560)
- basic: remove an assertion from cunescape_one (#1764560)
- journal: fix an off-by-one error in dev_kmsg_record (#1764560)
- tests: add a reproducer for a memory leak fixed in 30eddcd51b8a472e05d3b8d1 in August (#1764560)
- tests: add a reproducer for a heap-buffer-overflow fixed in 937b1171378bc1000a (#1764560)
- test: initialize syslog_fd in fuzz-journald-kmsg too (#1764560)
- tests: add a fuzzer for process_audit_string (#1764560)
- journald: check whether sscanf has changed the value corresponding to %n (#1764560)
- tests: introduce dummy_server_init and use it in all journald fuzzers (#1764560)
- tests: add a fuzzer for journald streams (#1764560)
- tests: add a fuzzer for server_process_native_file (#1764560)
- fuzz-journal-stream: avoid assertion failure on samples which don't fit in pipe (#1764560)
- journald: take leading spaces into account in syslog_parse_identifier (#1764560)
- Add a warning about the difference in permissions between existing directories and unit settings. (#1778384)
- execute: remove one redundant comparison check (#1778384)
- core: change ownership/mode of the execution directories also for static users (#1778384)
- core/dbus-execute: remove unnecessary initialization (#1734787)
- shared/cpu-set-util: move the part to print cpu-set into a separate function (#1734787)
- shared/cpu-set-util: remove now-unused CPU_SIZE_TO_NUM() (#1734787)
- Rework cpu affinity parsing (#1734787)
- Move cpus_in_affinity_mask() to cpu-set-util.[ch] (#1734787)
- test-cpu-set-util: add simple test for cpus_in_affinity_mask() (#1734787)
- test-cpu-set-util: add a smoke test for test_parse_cpu_set_extend() (#1734787)
- pid1: parse CPUAffinity= in incremental fashion (#1734787)
- pid1: don't reset setting from /proc/cmdline upon restart (#1734787)
- pid1: when reloading configuration, forget old settings (#1734787)
- test-execute: use CPUSet too (#1734787)
- shared/cpu-set-util: drop now-unused cleanup function (#1734787)
- shared/cpu-set-util: make transfer of cpu_set_t over bus endian safe (#1734787)
- test-cpu-set-util: add test for dbus conversions (#1734787)
- shared/cpu-set-util: introduce cpu_set_to_range() (#1734787)
- systemctl: present CPUAffinity mask as a list of CPU index ranges (#1734787)
- shared/cpu-set-util: only force range printing one time (#1734787)
- execute: dump CPUAffinity as a range string instead of a list of CPUs (#1734787)
- cpu-set-util: use %d-%d format in cpu_set_to_range_string() only for actual ranges (#1734787)
- core: introduce NUMAPolicy and NUMAMask options (#1734787)
- core: disable CPUAccounting by default (#1734787)
- set kptr_restrict=1 (#1689346)
- cryptsetup: reduce the chance that we will be OOM killed (#1696602)
- core, job: fix breakage of ordering dependencies by systemctl reload command (#1766417)
- debug-generator: enable custom systemd.debug_shell tty (#1723722)
* Thu Oct 24 2019 Lukas Nykryn <lnykryn@redhat.com> - 239-19
- core: never propagate reload failure to service result (#1735787)
- man: document systemd-analyze security (#1750343)
- man: reorder and add examples to systemd-analyze(1) (#1750343)
- travis: move to CentOS 8 docker images (#1761519)
- travis: drop SCL remains (#1761519)
- syslog: fix segfault in syslog_parse_priority() (#1761519)
- sd-bus: make strict asan shut up (#1761519)
- travis: don't run slow tests under ASan/UBSan (#1761519)
- kernel-install: do not require non-empty kernel cmdline (#1701454)
- ask-password: prevent buffer overrow when reading from keyring (#1752050)
- core: try to reopen /dev/kmsg again right after mounting /dev (#1749212)
- buildsys: don't garbage collect sections while linking (#1748258)
- udev: introduce CONST key name (#1762679)
- Call getgroups() to know size of supplementary groups array to allocate (#1743230256 KB
#1743235)
- Consider smb3 as remote filesystem (#1757257)
- process-util: introduce pid_is_my_child() helper (#1744972)
- core: reduce the number of stalled PIDs from the watched processes list when possible (#1744972)
- core: only watch processes when it's really necessary (#1744972)
- core: implement per unit journal rate limiting (#1719577)
- path: stop watching path specs once we triggered the target unit (#1763161)
- journald: fixed assertion failure when system journal rotation fails (#9893) (#1763619)
- test: use PBKDF2 instead of Argon2 in cryptsetup... (#1761519)
- test: mask several unnecessary services (#1761519)
- test: bump the second partition's size to 50M (#1761519)
- shared/sleep-config: exclude zram devices from hibernation candidates (#1763617)
- selinux: don't log SELINUX_INFO and SELINUX_WARNING messages to audit (#1763612)
- sd-device: introduce log_device_*() macros (#1753369)
- udev: Add id program and rule for FIDO security tokens (#1753369)
- shared/but-util: drop trusted annotation from bus_open_system_watch_bind_with_description() (#1746857)
- sd-bus: adjust indentation of comments (#1746857)
- resolved: do not run loop twice (#1746857)
- resolved: allow access to Set*Link and Revert methods through polkit (#1746857)
- resolved: query polkit only after parsing the data (#1746857)
* Fri Aug 30 2019 Lukas Nykryn <lnykryn@redhat.com> - 239-18
- shared/but-util: drop trusted annotation from bus_open_system_watch_bind_with_description() (#1746857)
- sd-bus: adjust indentation of comments (#1746857)
- resolved: do not run loop twice (#1746857)
- resolved: allow access to Set*Link and Revert methods through polkit (#1746857)
- resolved: query polkit only after parsing the data (#1746857)
* Wed Aug 07 2019 Lukas Nykryn <lnykryn@redhat.com> - 239-17
- mount: simplify /proc/self/mountinfo handler (#1696178)
- mount: rescan /proc/self/mountinfo before processing waitid() results (#1696178)
- swap: scan /proc/swaps before processing waitid() results (#1696178)
- analyze-security: fix potential division by zero (#1734400)
* Fri Jul 26 2019 Lukas Nykryn <lnykryn@redhat.com> - 239-16
- sd-bus: deal with cookie overruns (#1694999)
- journal-remote: do not request Content-Length if Transfer-Encoding is chunked (#1708849)
- journal: do not remove multiple spaces after identifier in syslog message (#1691817)
- cryptsetup: Do not fallback to PLAIN mapping if LUKS data device set fails. (#1719153)
- cryptsetup: call crypt_load() for LUKS only once (#1719153)
- cryptsetup: Add LUKS2 token support. (#1719153)
- udev/scsi_id: fix incorrect page length when get device identification VPD page (#1713227)
- Change job mode of manager triggered restarts to JOB_REPLACE (#11456
#1712524)
- bash-completion: analyze: support 'security' (#1733395)
- man: note that journal does not validate syslog fields (#1707175)
- rules: skip memory hotplug on ppc64 (#1713159)
* Thu May 23 2019 Lukas Nykryn <lnykryn@redhat.com> - 239-15
- tree-wide: shorten error logging a bit (#1697893)
- nspawn: simplify machine terminate bus call (#1697893)