diff options
Diffstat (limited to '')
80 files changed, 7657 insertions, 0 deletions
diff --git a/debian/patches/Fix-typo-in-function-name.patch b/debian/patches/Fix-typo-in-function-name.patch new file mode 100644 index 0000000..4f3c521 --- /dev/null +++ b/debian/patches/Fix-typo-in-function-name.patch @@ -0,0 +1,77 @@ +From: =?utf-8?q?Zbigniew_J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl> +Date: Tue, 4 Feb 2020 18:39:04 +0100 +Subject: Fix typo in function name + +(cherry picked from commit bc130b6858327b382b07b3985cf48e2aa9016b2d) +(cherry picked from commit b4eb8848240c3540180e4768216a0b884a5ed783) +(cherry picked from commit f14fa558ae9e139c94ee3af4a1ef1df313b2ff66) +(cherry picked from commit dd8aa0871d9cafa60a916d4ec01dd82d64edf7ed) +--- + TODO | 2 +- + src/libsystemd/sd-bus/bus-message.h | 2 +- + src/libsystemd/sd-bus/sd-bus.c | 8 ++++---- + src/shared/bus-polkit.c | 2 +- + 4 files changed, 7 insertions(+), 7 deletions(-) + +diff --git a/TODO b/TODO +index 462db57..327fead 100644 +--- a/TODO ++++ b/TODO +@@ -138,7 +138,7 @@ Features: + + * the a-posteriori stopping of units bound to units that disappeared logic + should be reworked: there should be a queue of units, and we should only +- enqeue stop jobs from a defer event that processes queue instead of ++ enqueue stop jobs from a defer event that processes queue instead of + right-away when we find a unit that is bound to one that doesn't exist + anymore. (similar to how the stop-unneeded queue has been reworked the same + way) +diff --git a/src/libsystemd/sd-bus/bus-message.h b/src/libsystemd/sd-bus/bus-message.h +index 7fd3f11..849d638 100644 +--- a/src/libsystemd/sd-bus/bus-message.h ++++ b/src/libsystemd/sd-bus/bus-message.h +@@ -211,4 +211,4 @@ int bus_message_remarshal(sd_bus *bus, sd_bus_message **m); + + void bus_message_set_sender_driver(sd_bus *bus, sd_bus_message *m); + void bus_message_set_sender_local(sd_bus *bus, sd_bus_message *m); +-int sd_bus_enqeue_for_read(sd_bus *bus, sd_bus_message *m); ++int sd_bus_enqueue_for_read(sd_bus *bus, sd_bus_message *m); +diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c +index 94380af..c20adcf 100644 +--- a/src/libsystemd/sd-bus/sd-bus.c ++++ b/src/libsystemd/sd-bus/sd-bus.c +@@ -4145,7 +4145,7 @@ _public_ int sd_bus_get_close_on_exit(sd_bus *bus) { + return bus->close_on_exit; + } + +-int sd_bus_enqeue_for_read(sd_bus *bus, sd_bus_message *m) { ++int sd_bus_enqueue_for_read(sd_bus *bus, sd_bus_message *m) { + int r; + + assert_return(bus, -EINVAL); +@@ -4157,9 +4157,9 @@ int sd_bus_enqeue_for_read(sd_bus *bus, sd_bus_message *m) { + if (!BUS_IS_OPEN(bus->state)) + return -ENOTCONN; + +- /* Re-enqeue a message for reading. This is primarily useful for PolicyKit-style authentication, +- * where we want accept a message, then determine we need to interactively authenticate the user, and +- * when we have that process the message again. */ ++ /* Re-enqueue a message for reading. This is primarily useful for PolicyKit-style authentication, ++ * where we accept a message, then determine we need to interactively authenticate the user, and then ++ * we want to process the message again. */ + + r = bus_rqueue_make_room(bus); + if (r < 0) +diff --git a/src/shared/bus-polkit.c b/src/shared/bus-polkit.c +index 02c11aa..d1d2456 100644 +--- a/src/shared/bus-polkit.c ++++ b/src/shared/bus-polkit.c +@@ -236,7 +236,7 @@ static int async_polkit_callback(sd_bus_message *reply, void *userdata, sd_bus_e + if (r < 0) + goto fail; + +- r = sd_bus_enqeue_for_read(sd_bus_message_get_bus(q->request), q->request); ++ r = sd_bus_enqueue_for_read(sd_bus_message_get_bus(q->request), q->request); + if (r < 0) + goto fail; + diff --git a/debian/patches/Re-add-uaccess-tag-for-dev-dri-renderD.patch b/debian/patches/Re-add-uaccess-tag-for-dev-dri-renderD.patch new file mode 100644 index 0000000..58d2b5d --- /dev/null +++ b/debian/patches/Re-add-uaccess-tag-for-dev-dri-renderD.patch @@ -0,0 +1,49 @@ +From: Michael Biebl <biebl@debian.org> +Date: Wed, 13 Mar 2019 23:22:26 +0100 +Subject: Re-add uaccess tag for /dev/dri/renderD* + +Setting an access mode != 0666 is explicitly supported via -Dgroup-render-mode +In such a case, re-add the uaccess tag. + +This is basically the same change that was done for /dev/kvm in +commit fa53e24130af3a389573acb9585eadbf7192955f and +ace5e3111c0b8d8bfd84b32f2c689b0a4d92c061 +and partially reverts the changes from +4e15a7343cb389e97f3eb4f49699161862d8b8b2 + +(cherry picked from commit 055a083a47de968744c4988fe305592477118c86) +--- + meson.build | 4 +++- + src/login/70-uaccess.rules.m4 | 4 ++++ + 2 files changed, 7 insertions(+), 1 deletion(-) + +diff --git a/meson.build b/meson.build +index 56c98b9..d340736 100644 +--- a/meson.build ++++ b/meson.build +@@ -818,7 +818,9 @@ conf.set10('ENABLE_WHEEL_GROUP', get_option('wheel-group')) + dev_kvm_mode = get_option('dev-kvm-mode') + substs.set('DEV_KVM_MODE', dev_kvm_mode) + conf.set10('DEV_KVM_UACCESS', dev_kvm_mode != '0666') +-substs.set('GROUP_RENDER_MODE', get_option('group-render-mode')) ++group_render_mode = get_option('group-render-mode') ++substs.set('GROUP_RENDER_MODE', group_render_mode) ++conf.set10('GROUP_RENDER_UACCESS', group_render_mode != '0666') + + kill_user_processes = get_option('default-kill-user-processes') + conf.set10('KILL_USER_PROCESSES', kill_user_processes) +diff --git a/src/login/70-uaccess.rules.m4 b/src/login/70-uaccess.rules.m4 +index d55e5bf..4bb144a 100644 +--- a/src/login/70-uaccess.rules.m4 ++++ b/src/login/70-uaccess.rules.m4 +@@ -46,6 +46,10 @@ SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x014001*", TAG+="uaccess" + + # DRI video devices + SUBSYSTEM=="drm", KERNEL=="card*", TAG+="uaccess" ++m4_ifdef(`GROUP_RENDER_UACCESS',`` ++# DRI render nodes ++SUBSYSTEM=="drm", KERNEL=="renderD*", TAG+="uaccess"'' ++)m4_dnl + m4_ifdef(`DEV_KVM_UACCESS',`` + # KVM + SUBSYSTEM=="misc", KERNEL=="kvm", TAG+="uaccess"'' diff --git a/debian/patches/ask-password-prevent-buffer-overflow-when-reading-from-ke.patch b/debian/patches/ask-password-prevent-buffer-overflow-when-reading-from-ke.patch new file mode 100644 index 0000000..dc46353 --- /dev/null +++ b/debian/patches/ask-password-prevent-buffer-overflow-when-reading-from-ke.patch @@ -0,0 +1,32 @@ +From: Michael Biebl <biebl@debian.org> +Date: Thu, 27 Jun 2019 15:02:40 +0200 +Subject: ask-password: prevent buffer overflow 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) +--- + 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 072bf72..97a800f 100644 +--- a/src/shared/ask-password-api.c ++++ b/src/shared/ask-password-api.c +@@ -81,7 +81,7 @@ static int retrieve_key(key_serial_t serial, char ***ret) { + if (n < m) + break; + +- explicit_bzero_safe(p, n); ++ explicit_bzero_safe(p, m); + free(p); + m *= 2; + } diff --git a/debian/patches/bash-completion-use-default-completion-for-redirect-opera.patch b/debian/patches/bash-completion-use-default-completion-for-redirect-opera.patch new file mode 100644 index 0000000..053ed73 --- /dev/null +++ b/debian/patches/bash-completion-use-default-completion-for-redirect-opera.patch @@ -0,0 +1,27 @@ +From: Frantisek Sumsal <frantisek@sumsal.cz> +Date: Sat, 23 Mar 2019 21:49:17 +0100 +Subject: bash-completion: use default completion for redirect operators + +(cherry picked from commit 1413763ea540a897852494259cb949fe01e1e7e7) +--- + shell-completion/bash/journalctl | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/shell-completion/bash/journalctl b/shell-completion/bash/journalctl +index bcd4533..5a6a3da 100644 +--- a/shell-completion/bash/journalctl ++++ b/shell-completion/bash/journalctl +@@ -52,6 +52,13 @@ _journalctl() { + --vacuum-size --vacuum-time --vacuum-files --output-fields' + ) + ++ # Use the default completion for shell redirect operators ++ if __contains_word "$prev" '>' '>>' '&>'; then ++ compopt -o filenames ++ COMPREPLY=( $(compgen -f -- "$cur") ) ++ return 0; ++ fi ++ + if __contains_word "$prev" ${OPTS[ARG]} ${OPTS[ARGUNKNOWN]}; then + case $prev in + --boot|-b) diff --git a/debian/patches/basic-cap-list-parse-print-numerical-capabilities.patch b/debian/patches/basic-cap-list-parse-print-numerical-capabilities.patch new file mode 100644 index 0000000..3b9eb09 --- /dev/null +++ b/debian/patches/basic-cap-list-parse-print-numerical-capabilities.patch @@ -0,0 +1,87 @@ +From: =?utf-8?q?Zbigniew_J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl> +Date: Thu, 9 Jul 2020 23:15:47 +0200 +Subject: basic/cap-list: parse/print numerical capabilities + +We would refuse to print capabilities which were didn't have a name +for. The kernel adds new capabilities from time to time, most recently +cap_bpf. 'systmectl show -p CapabilityBoundingSet ...' would fail with +"Failed to parse bus message: Invalid argument" because +capability_set_to_string_alloc() would fail with -EINVAL. So let's +print such capabilities in hexadecimal: + +CapabilityBoundingSet=cap_chown cap_dac_override cap_dac_read_search + cap_fowner cap_fsetid cap_kill cap_setgid cap_setuid cap_setpcap + cap_linux_immutable cap_net_bind_service cap_net_broadcast cap_net_admin + cap_net_raw cap_ipc_lock cap_ipc_owner 0x10 0x11 0x12 0x13 0x14 0x15 0x16 + 0x17 0x18 0x19 0x1a ... + +For symmetry, also allow capabilities that we don't know to be specified. + +Fixes https://bugzilla.redhat.com/show_bug.cgi?id=1853736. + +(cherry picked from commit 417770f3033c426ca848b158d0bf057cd8ad1329) +--- + src/basic/cap-list.c | 10 +++++++--- + src/test/test-cap-list.c | 4 +++- + 2 files changed, 10 insertions(+), 4 deletions(-) + +diff --git a/src/basic/cap-list.c b/src/basic/cap-list.c +index 29a17d9..b72b037 100644 +--- a/src/basic/cap-list.c ++++ b/src/basic/cap-list.c +@@ -10,6 +10,7 @@ + #include "macro.h" + #include "missing.h" + #include "parse-util.h" ++#include "stdio-util.h" + #include "util.h" + + static const struct capability_name* lookup_capability(register const char *str, register GPERF_LEN_TYPE len); +@@ -37,7 +38,7 @@ int capability_from_name(const char *name) { + /* Try to parse numeric capability */ + r = safe_atoi(name, &i); + if (r >= 0) { +- if (i >= 0 && (size_t) i < ELEMENTSOF(capability_names)) ++ if (i >= 0 && i < 64) + return i; + else + return -EINVAL; +@@ -65,11 +66,14 @@ int capability_set_to_string_alloc(uint64_t set, char **s) { + for (i = 0; i < cap_last_cap(); i++) + if (set & (UINT64_C(1) << i)) { + const char *p; ++ char buf[2 + 16 + 1]; + size_t add; + + p = capability_to_name(i); +- if (!p) +- return -EINVAL; ++ if (!p) { ++ xsprintf(buf, "0x%lx", i); ++ p = buf; ++ } + + add = strlen(p); + +diff --git a/src/test/test-cap-list.c b/src/test/test-cap-list.c +index de5fa72..84bbb7b 100644 +--- a/src/test/test-cap-list.c ++++ b/src/test/test-cap-list.c +@@ -30,6 +30,8 @@ static void test_cap_list(void) { + assert_se(capability_from_name("cAp_aUdIt_rEAd") == CAP_AUDIT_READ); + assert_se(capability_from_name("0") == 0); + assert_se(capability_from_name("15") == 15); ++ assert_se(capability_from_name("63") == 63); ++ assert_se(capability_from_name("64") == -EINVAL); + assert_se(capability_from_name("-1") == -EINVAL); + + for (i = 0; i < capability_list_length(); i++) { +@@ -64,7 +66,7 @@ static void test_capability_set_one(uint64_t c, const char *t) { + + free(t1); + assert_se(t1 = strjoin("'cap_chown cap_dac_override' \"cap_setgid cap_setuid\"", t, +- " hogehoge foobar 12345 3.14 -3 ", t)); ++ " hogehoge foobar 18446744073709551616 3.14 -3 ", t)); + assert_se(capability_set_from_string(t1, &c1) == 0); + assert_se(c1 == c_masked); + } diff --git a/debian/patches/basic-unit-name-do-not-use-strdupa-on-a-path.patch b/debian/patches/basic-unit-name-do-not-use-strdupa-on-a-path.patch new file mode 100644 index 0000000..0faa7d1 --- /dev/null +++ b/debian/patches/basic-unit-name-do-not-use-strdupa-on-a-path.patch @@ -0,0 +1,64 @@ +From bae2f0d1109a8c75a7fb89ae6b8d1b6ef8dfab16 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl> +Date: Wed, 23 Jun 2021 11:46:41 +0200 +Subject: basic/unit-name: do not use strdupa() on a path + +The path may have unbounded length, for example through a fuse mount. + +CVE-2021-33910: attacked controlled alloca() leads to crash in systemd and +ultimately a kernel panic. Systemd parses the content of /proc/self/mountinfo +and each mountpoint is passed to mount_setup_unit(), which calls +unit_name_path_escape() underneath. A local attacker who is able to mount a +filesystem with a very long path can crash systemd and the whole system. + +https://bugzilla.redhat.com/show_bug.cgi?id=1970887 + +The resulting string length is bounded by UNIT_NAME_MAX, which is 256. But we +can't easily check the length after simplification before doing the +simplification, which in turns uses a copy of the string we can write to. +So we can't reject paths that are too long before doing the duplication. +Hence the most obvious solution is to switch back to strdup(), as before +7410616cd9dbbec97cf98d75324da5cda2b2f7a2. +--- + src/basic/unit-name.c | 13 +++++-------- + 1 file changed, 5 insertions(+), 8 deletions(-) + +diff --git a/src/basic/unit-name.c b/src/basic/unit-name.c +index 284a77348316..a22763443fdd 100644 +--- a/src/basic/unit-name.c ++++ b/src/basic/unit-name.c +@@ -378,12 +378,13 @@ int unit_name_unescape(const char *f, char **ret) { + } + + int unit_name_path_escape(const char *f, char **ret) { +- char *p, *s; ++ _cleanup_free_ char *p = NULL; ++ char *s; + + assert(f); + assert(ret); + +- p = strdupa(f); ++ p = strdup(f); + if (!p) + return -ENOMEM; + +@@ -395,13 +396,9 @@ int unit_name_path_escape(const char *f, char **ret) { + if (!path_is_normalized(p)) + return -EINVAL; + +- /* Truncate trailing slashes */ ++ /* Truncate trailing slashes and skip leading slashes */ + delete_trailing_chars(p, "/"); +- +- /* Truncate leading slashes */ +- p = skip_leading_chars(p, "/"); +- +- s = unit_name_escape(p); ++ s = unit_name_escape(skip_leading_chars(p, "/")); + } + if (!s) + return -ENOMEM; +-- +2.32.0 + diff --git a/debian/patches/bus-polkit-rename-return-error-parameter-to-ret_error.patch b/debian/patches/bus-polkit-rename-return-error-parameter-to-ret_error.patch new file mode 100644 index 0000000..a7c9cc5 --- /dev/null +++ b/debian/patches/bus-polkit-rename-return-error-parameter-to-ret_error.patch @@ -0,0 +1,67 @@ +From: Lennart Poettering <lennart@poettering.net> +Date: Wed, 22 Jan 2020 14:29:43 +0100 +Subject: bus-polkit: rename return error parameter to ret_error + +(cherry picked from commit 773b1a7916bfce3aa2a21ecf534d475032e8528e) +(cherry picked from commit 5b2442d5c3ec1c86a3a8d1c1abe3234a570ba5e6) +(cherry picked from commit 4441844d5889a39d9d059c30e5d94c916d9d6735) +(cherry picked from commit 816d5e2d6dd83a3bd0ff56a352295831cb937198) +--- + src/shared/bus-polkit.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/src/shared/bus-polkit.c b/src/shared/bus-polkit.c +index da4aee5..f93aa17 100644 +--- a/src/shared/bus-polkit.c ++++ b/src/shared/bus-polkit.c +@@ -37,7 +37,7 @@ int bus_test_polkit( + const char **details, + uid_t good_user, + bool *_challenge, +- sd_bus_error *e) { ++ sd_bus_error *ret_error) { + + int r; + +@@ -102,11 +102,11 @@ int bus_test_polkit( + if (r < 0) + return r; + +- r = sd_bus_call(call->bus, request, 0, e, &reply); ++ r = sd_bus_call(call->bus, request, 0, ret_error, &reply); + if (r < 0) { + /* Treat no PK available as access denied */ +- if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN)) { +- sd_bus_error_free(e); ++ if (sd_bus_error_has_name(ret_error, SD_BUS_ERROR_SERVICE_UNKNOWN)) { ++ sd_bus_error_free(ret_error); + return -EACCES; + } + +@@ -196,7 +196,7 @@ int bus_verify_polkit_async( + bool interactive, + uid_t good_user, + Hashmap **registry, +- sd_bus_error *error) { ++ sd_bus_error *ret_error) { + + #if ENABLE_POLKIT + _cleanup_(sd_bus_message_unrefp) sd_bus_message *pk = NULL; +@@ -237,7 +237,7 @@ int bus_verify_polkit_async( + return -EACCES; + + /* Copy error from polkit reply */ +- sd_bus_error_copy(error, e); ++ sd_bus_error_copy(ret_error, e); + return -sd_bus_error_get_errno(e); + } + +@@ -251,7 +251,7 @@ int bus_verify_polkit_async( + return 1; + + if (challenge) +- return sd_bus_error_set(error, SD_BUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED, "Interactive authentication required."); ++ return sd_bus_error_set(ret_error, SD_BUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED, "Interactive authentication required."); + + return -EACCES; + } diff --git a/debian/patches/bus-util-treat-org.freedesktop.DBus.Error.ServiceUnknown-.patch b/debian/patches/bus-util-treat-org.freedesktop.DBus.Error.ServiceUnknown-.patch new file mode 100644 index 0000000..ffd349f --- /dev/null +++ b/debian/patches/bus-util-treat-org.freedesktop.DBus.Error.ServiceUnknown-.patch @@ -0,0 +1,34 @@ +From: Yu Watanabe <watanabe.yu+github@gmail.com> +Date: Thu, 4 Apr 2019 13:35:29 +0900 +Subject: bus-util: treat org.freedesktop.DBus.Error.ServiceUnknown nicely + when polkit does not exist + +Fixes #12209. + +(cherry picked from commit 8c69fe79df6394f6b8b8d0bb536a265caf417868) +(cherry picked from commit 0bb488b22144aeb87d93e97123f71babe116261f) +--- + src/shared/bus-util.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c +index 9d31fba..a406dd8 100644 +--- a/src/shared/bus-util.c ++++ b/src/shared/bus-util.c +@@ -410,14 +410,14 @@ int bus_verify_polkit_async( + if (sd_bus_message_is_method_error(q->reply, NULL)) { + const sd_bus_error *e; + +- /* Copy error from polkit reply */ + e = sd_bus_message_get_error(q->reply); +- sd_bus_error_copy(error, e); + + /* Treat no PK available as access denied */ + if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN)) + return -EACCES; + ++ /* Copy error from polkit reply */ ++ sd_bus_error_copy(error, e); + return -sd_bus_error_get_errno(e); + } + diff --git a/debian/patches/cgtop-Fix-processing-of-controllers-other-than-CPU.patch b/debian/patches/cgtop-Fix-processing-of-controllers-other-than-CPU.patch new file mode 100644 index 0000000..f18ecb2 --- /dev/null +++ b/debian/patches/cgtop-Fix-processing-of-controllers-other-than-CPU.patch @@ -0,0 +1,169 @@ +From: Szabolcs Fruhwald <sfruhwald@google.com> +Date: Wed, 20 Feb 2019 12:38:50 -0800 +Subject: cgtop: Fix processing of controllers other than CPU + +After debugging the issue with gdb, I found that the following change + + 94ddb08 "cgtop: Still try to get CPU statistics if controller-free" + +has introduced a bug, which prevents process(..) method processing +memory and io controllers when cpu_accounting_is_cheap() is true. +The obvious fix is to move this branch to be the last one, keeping +the intended behavior of the above change, without having a negative +effect on the other controllers. + +Fixes #11773 [systemd-cgtop no longer shows memory (and io) usage] + +(cherry picked from commit 5fe74e893c7939a360dc4eb75dbf3f540526c968) +--- + src/cgtop/cgtop.c | 130 +++++++++++++++++++++++++++--------------------------- + 1 file changed, 65 insertions(+), 65 deletions(-) + +diff --git a/src/cgtop/cgtop.c b/src/cgtop/cgtop.c +index b3bda30..ab3b979 100644 +--- a/src/cgtop/cgtop.c ++++ b/src/cgtop/cgtop.c +@@ -223,71 +223,6 @@ static int process( + if (g->n_tasks > 0) + g->n_tasks_valid = true; + +- } else if (STR_IN_SET(controller, "cpu", "cpuacct") || cpu_accounting_is_cheap()) { +- _cleanup_free_ char *p = NULL, *v = NULL; +- uint64_t new_usage; +- nsec_t timestamp; +- +- if (is_root_cgroup(path)) { +- r = procfs_cpu_get_usage(&new_usage); +- if (r < 0) +- return r; +- } else if (all_unified) { +- _cleanup_free_ char *val = NULL; +- +- if (!streq(controller, "cpu")) +- return 0; +- +- r = cg_get_keyed_attribute("cpu", path, "cpu.stat", STRV_MAKE("usage_usec"), &val); +- if (IN_SET(r, -ENOENT, -ENXIO)) +- return 0; +- if (r < 0) +- return r; +- +- r = safe_atou64(val, &new_usage); +- if (r < 0) +- return r; +- +- new_usage *= NSEC_PER_USEC; +- } else { +- if (!streq(controller, "cpuacct")) +- return 0; +- +- r = cg_get_path(controller, path, "cpuacct.usage", &p); +- if (r < 0) +- return r; +- +- r = read_one_line_file(p, &v); +- if (r == -ENOENT) +- return 0; +- if (r < 0) +- return r; +- +- r = safe_atou64(v, &new_usage); +- if (r < 0) +- return r; +- } +- +- timestamp = now_nsec(CLOCK_MONOTONIC); +- +- if (g->cpu_iteration == iteration - 1 && +- (nsec_t) new_usage > g->cpu_usage) { +- +- nsec_t x, y; +- +- x = timestamp - g->cpu_timestamp; +- if (x < 1) +- x = 1; +- +- y = (nsec_t) new_usage - g->cpu_usage; +- g->cpu_fraction = (double) y / (double) x; +- g->cpu_valid = true; +- } +- +- g->cpu_usage = (nsec_t) new_usage; +- g->cpu_timestamp = timestamp; +- g->cpu_iteration = iteration; +- + } else if (streq(controller, "memory")) { + + if (is_root_cgroup(path)) { +@@ -411,6 +346,71 @@ static int process( + g->io_output = wr; + g->io_timestamp = timestamp; + g->io_iteration = iteration; ++ } else if (STR_IN_SET(controller, "cpu", "cpuacct") || cpu_accounting_is_cheap()) { ++ _cleanup_free_ char *p = NULL, *v = NULL; ++ uint64_t new_usage; ++ nsec_t timestamp; ++ ++ if (is_root_cgroup(path)) { ++ r = procfs_cpu_get_usage(&new_usage); ++ if (r < 0) ++ return r; ++ } else if (all_unified) { ++ _cleanup_free_ char *val = NULL; ++ ++ if (!streq(controller, "cpu")) ++ return 0; ++ ++ r = cg_get_keyed_attribute("cpu", path, "cpu.stat", STRV_MAKE("usage_usec"), &val); ++ if (IN_SET(r, -ENOENT, -ENXIO)) ++ return 0; ++ if (r < 0) ++ return r; ++ ++ r = safe_atou64(val, &new_usage); ++ if (r < 0) ++ return r; ++ ++ new_usage *= NSEC_PER_USEC; ++ } else { ++ if (!streq(controller, "cpuacct")) ++ return 0; ++ ++ r = cg_get_path(controller, path, "cpuacct.usage", &p); ++ if (r < 0) ++ return r; ++ ++ r = read_one_line_file(p, &v); ++ if (r == -ENOENT) ++ return 0; ++ if (r < 0) ++ return r; ++ ++ r = safe_atou64(v, &new_usage); ++ if (r < 0) ++ return r; ++ } ++ ++ timestamp = now_nsec(CLOCK_MONOTONIC); ++ ++ if (g->cpu_iteration == iteration - 1 && ++ (nsec_t) new_usage > g->cpu_usage) { ++ ++ nsec_t x, y; ++ ++ x = timestamp - g->cpu_timestamp; ++ if (x < 1) ++ x = 1; ++ ++ y = (nsec_t) new_usage - g->cpu_usage; ++ g->cpu_fraction = (double) y / (double) x; ++ g->cpu_valid = true; ++ } ++ ++ g->cpu_usage = (nsec_t) new_usage; ++ g->cpu_timestamp = timestamp; ++ g->cpu_iteration = iteration; ++ + } + + if (ret) diff --git a/debian/patches/core-change-ownership-mode-of-the-execution-directories-a.patch b/debian/patches/core-change-ownership-mode-of-the-execution-directories-a.patch new file mode 100644 index 0000000..6f8b0fc --- /dev/null +++ b/debian/patches/core-change-ownership-mode-of-the-execution-directories-a.patch @@ -0,0 +1,85 @@ +From: Lennart Poettering <lennart@poettering.net> +Date: Thu, 14 Mar 2019 17:19:30 +0100 +Subject: 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) +--- + 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 5486e37..5c3930e 100644 +--- a/src/core/execute.c ++++ b/src/core/execute.c +@@ -2151,37 +2151,42 @@ static int setup_exec_directory( + if (r < 0) + goto fail; + +- /* Lock down the access mode */ +- if (chmod(pp, context->directories[type].mode) < 0) { +- r = -errno; +- goto fail; +- } + } else { + r = mkdir_label(p, context->directories[type].mode); + if (r < 0) { +- struct stat st; +- + if (r != -EEXIST) + goto fail; + +- if (stat(p, &st) < 0) { +- r = -errno; +- goto fail; +- } +- if (((st.st_mode ^ context->directories[type].mode) & 07777) != 0) +- log_warning("%s \'%s\' already exists but the mode is different. " +- "(filesystem: %o %sMode: %o)", +- exec_directory_type_to_string(type), *rt, +- st.st_mode & 07777, exec_directory_type_to_string(type), context->directories[type].mode & 07777); +- if (!context->dynamic_user) ++ if (type == EXEC_DIRECTORY_CONFIGURATION) { ++ struct stat st; ++ ++ /* Don't change the owner/access mode of the configuration directory, ++ * as in the common case it is not written to by a service, and shall ++ * not be writable. */ ++ ++ if (stat(p, &st) < 0) { ++ r = -errno; ++ goto fail; ++ } ++ ++ /* Still complain if the access mode doesn't match */ ++ if (((st.st_mode ^ context->directories[type].mode) & 07777) != 0) ++ log_warning("%s \'%s\' already exists but the mode is different. " ++ "(File system: %o %sMode: %o)", ++ exec_directory_type_to_string(type), *rt, ++ st.st_mode & 07777, exec_directory_type_to_string(type), context->directories[type].mode & 07777); ++ + continue; ++ } + } + } + +- /* Don't change the owner of the configuration directory, as in the common case it is not written to by +- * a service, and shall not be writable. */ +- if (type == EXEC_DIRECTORY_CONFIGURATION) +- continue; ++ /* Lock down the access mode (we use chmod_and_chown() to make this idempotent. We don't ++ * specifiy UID/GID here, so that path_chown_recursive() can optimize things depending on the ++ * current UID/GID ownership.) */ ++ r = chmod_and_chown(pp ?: p, context->directories[type].mode, UID_INVALID, GID_INVALID); ++ if (r < 0) ++ goto fail; + + /* Then, change the ownership of the whole tree, if necessary */ + r = path_chown_recursive(pp ?: p, uid, gid); diff --git a/debian/patches/core-factor-root_directory-application-out-of-apply_worki.patch b/debian/patches/core-factor-root_directory-application-out-of-apply_worki.patch new file mode 100644 index 0000000..3ee945a --- /dev/null +++ b/debian/patches/core-factor-root_directory-application-out-of-apply_worki.patch @@ -0,0 +1,89 @@ +From: Joerg Behrmann <behrmann@physik.fu-berlin.de> +Date: Fri, 21 Jun 2019 13:51:53 +0200 +Subject: core: factor root_directory application out of + apply_working_directory + +Fixes: #12498 +(cherry picked from commit fa97f63067a05b4e793fd4e0a2b54797459b4812) +--- + src/core/execute.c | 38 ++++++++++++++++++++++++++++---------- + 1 file changed, 28 insertions(+), 10 deletions(-) + +diff --git a/src/core/execute.c b/src/core/execute.c +index a708231..47518f4 100644 +--- a/src/core/execute.c ++++ b/src/core/execute.c +@@ -2480,7 +2480,6 @@ static int apply_working_directory( + const ExecContext *context, + const ExecParameters *params, + const char *home, +- const bool needs_mount_ns, + int *exit_status) { + + const char *d, *wd; +@@ -2502,15 +2501,9 @@ static int apply_working_directory( + else + wd = "/"; + +- if (params->flags & EXEC_APPLY_CHROOT) { +- if (!needs_mount_ns && context->root_directory) +- if (chroot(context->root_directory) < 0) { +- *exit_status = EXIT_CHROOT; +- return -errno; +- } +- ++ if (params->flags & EXEC_APPLY_CHROOT) + d = wd; +- } else ++ else + d = prefix_roota(context->root_directory, wd); + + if (chdir(d) < 0 && !context->working_directory_missing_ok) { +@@ -2521,6 +2514,26 @@ static int apply_working_directory( + return 0; + } + ++static int apply_root_directory( ++ const ExecContext *context, ++ const ExecParameters *params, ++ const bool needs_mount_ns, ++ int *exit_status) { ++ ++ assert(context); ++ assert(exit_status); ++ ++ if (params->flags & EXEC_APPLY_CHROOT) { ++ if (!needs_mount_ns && context->root_directory) ++ if (chroot(context->root_directory) < 0) { ++ *exit_status = EXIT_CHROOT; ++ return -errno; ++ } ++ } ++ ++ return 0; ++} ++ + static int setup_keyring( + const Unit *u, + const ExecContext *context, +@@ -3425,6 +3438,11 @@ static int exec_child( + } + } + ++ /* chroot to root directory first, before we lose the ability to chroot */ ++ r = apply_root_directory(context, params, needs_mount_namespace, exit_status); ++ if (r < 0) ++ return log_unit_error_errno(unit, r, "Chrooting to the requested root directory failed: %m"); ++ + if (needs_setuid) { + if (context->user) { + r = enforce_user(context, uid); +@@ -3457,7 +3475,7 @@ static int exec_child( + + /* Apply working directory here, because the working directory might be on NFS and only the user running + * this service might have the correct privilege to change to the working directory */ +- r = apply_working_directory(context, params, home, needs_mount_namespace, exit_status); ++ r = apply_working_directory(context, params, home, exit_status); + if (r < 0) + return log_unit_error_errno(unit, r, "Changing to the requested working directory failed: %m"); + diff --git a/debian/patches/core-make-sure-to-restore-the-control-command-id-too.patch b/debian/patches/core-make-sure-to-restore-the-control-command-id-too.patch new file mode 100644 index 0000000..5df25ac --- /dev/null +++ b/debian/patches/core-make-sure-to-restore-the-control-command-id-too.patch @@ -0,0 +1,27 @@ +From: Lennart Poettering <lennart@poettering.net> +Date: Wed, 22 Apr 2020 20:34:02 +0200 +Subject: core: make sure to restore the control command id, too + +Fixes: #15356 +(cherry picked from commit e9da62b18af647bfa73807e1c7fc3bfa4bb4b2ac) +--- + src/core/service.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/src/core/service.c b/src/core/service.c +index 5f5bcb3..eb66884 100644 +--- a/src/core/service.c ++++ b/src/core/service.c +@@ -2689,9 +2689,10 @@ static int service_deserialize_exec_command(Unit *u, const char *key, const char + break; + } + +- if (command && control) ++ if (command && control) { + s->control_command = command; +- else if (command) ++ s->control_command_id = id; ++ } else if (command) + s->main_command = command; + else + log_unit_warning(u, "Current command vanished from the unit file, execution of the command list won't be resumed."); diff --git a/debian/patches/core-never-propagate-reload-failure-to-service-result.patch b/debian/patches/core-never-propagate-reload-failure-to-service-result.patch new file mode 100644 index 0000000..062434d --- /dev/null +++ b/debian/patches/core-never-propagate-reload-failure-to-service-result.patch @@ -0,0 +1,23 @@ +From: Lennart Poettering <lennart@poettering.net> +Date: Wed, 17 Jul 2019 19:16:33 +0200 +Subject: core: never propagate reload failure to service result + +Fixes: #11238 +(cherry picked from commit d611cfa748aaf600832160132774074e808c82c7) +--- + 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 324dcf2..5f5bcb3 100644 +--- a/src/core/service.c ++++ b/src/core/service.c +@@ -3335,7 +3335,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { + service_exec_command_to_string(s->control_command_id), + code, status); + +- if (s->result == SERVICE_SUCCESS) ++ if (s->state != SERVICE_RELOAD && s->result == SERVICE_SUCCESS) + s->result = f; + + if (s->control_command && diff --git a/debian/patches/core-set-fs.file-max-sysctl-to-LONG_MAX-rather-than-ULONG.patch b/debian/patches/core-set-fs.file-max-sysctl-to-LONG_MAX-rather-than-ULONG.patch new file mode 100644 index 0000000..6465a1f --- /dev/null +++ b/debian/patches/core-set-fs.file-max-sysctl-to-LONG_MAX-rather-than-ULONG.patch @@ -0,0 +1,34 @@ +From: Lennart Poettering <lennart@poettering.net> +Date: Mon, 17 Jun 2019 10:51:25 +0200 +Subject: core: set fs.file-max sysctl to LONG_MAX rather than ULONG_MAX + +Since kernel 5.2 the kernel thankfully returns proper errors when we +write a value out of range to the sysctl. Which however breaks writing +ULONG_MAX to request the maximum value. Hence let's write the new +maximum value instead, LONG_MAX. + +/cc @brauner + +Fixes: #12803 +(cherry picked from commit 6e2f78948403a4cce45b9e34311c9577c624f066) +--- + src/core/main.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/core/main.c b/src/core/main.c +index bc7fcc6..255e204 100644 +--- a/src/core/main.c ++++ b/src/core/main.c +@@ -1200,9 +1200,9 @@ static void bump_file_max_and_nr_open(void) { + #endif + + #if BUMP_PROC_SYS_FS_FILE_MAX +- /* I so wanted to use STRINGIFY(ULONG_MAX) here, but alas we can't as glibc/gcc define that as +- * "(0x7fffffffffffffffL * 2UL + 1UL)". Seriously. 😢 */ +- if (asprintf(&t, "%lu\n", ULONG_MAX) < 0) { ++ /* The maximum the kernel allows for this since 5.2 is LONG_MAX, use that. (Previously thing where ++ * different but the operation would fail silently.) */ ++ if (asprintf(&t, "%li\n", LONG_MAX) < 0) { + log_oom(); + return; + } diff --git a/debian/patches/core-unset-HOME-that-the-kernel-gives-us.patch b/debian/patches/core-unset-HOME-that-the-kernel-gives-us.patch new file mode 100644 index 0000000..8ef74c1 --- /dev/null +++ b/debian/patches/core-unset-HOME-that-the-kernel-gives-us.patch @@ -0,0 +1,30 @@ +From: =?utf-8?q?Zbigniew_J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl> +Date: Tue, 21 May 2019 19:26:12 +0200 +Subject: core: unset HOME=/ that the kernel gives us + +Partially fixes #12389. + +%h would return "/" in a machine, but "/root" in a container. Let's fix +this by resetting $HOME to the expected value. + +(cherry picked from commit 9d48671c62de133a2b9fe7c31e70c0ff8e68f2db) +--- + src/core/main.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/src/core/main.c b/src/core/main.c +index 561f956..bc7fcc6 100644 +--- a/src/core/main.c ++++ b/src/core/main.c +@@ -1503,6 +1503,11 @@ static int fixup_environment(void) { + if (setenv("TERM", t, 1) < 0) + return -errno; + ++ /* The kernels sets HOME=/ for init. Let's undo this. */ ++ if (path_equal_ptr(getenv("HOME"), "/") && ++ unsetenv("HOME") < 0) ++ log_warning_errno(errno, "Failed to unset $HOME: %m"); ++ + return 0; + } + diff --git a/debian/patches/debian/Add-env-variable-for-machine-ID-path.patch b/debian/patches/debian/Add-env-variable-for-machine-ID-path.patch new file mode 100644 index 0000000..06d83d5 --- /dev/null +++ b/debian/patches/debian/Add-env-variable-for-machine-ID-path.patch @@ -0,0 +1,77 @@ +From: Martin Pitt <mpitt@debian.org> +Date: Wed, 18 Jan 2017 11:21:35 +0100 +Subject: Add env variable for machine ID path + +During package build, in minimal chroots, or other systems which do not already +have an /etc/machine-id we get six test failures. Introduce a +$SYSTEMD_MACHINE_ID_PATH environment variable which can specify a location +other than /etc/machine-id, so that the unit tests are independent from the +environment. + +Also adjust test-fs-util to not assume that /etc/machine-id exists. Use +/etc/passwd instead which is created by base-files. + +Closes: #851445 + +Bug: https://bugs.freedesktop.org/show_bug.cgi?id=62344 +--- + src/libsystemd/sd-id128/sd-id128.c | 2 +- + src/test/test-fs-util.c | 11 +++++++---- + 2 files changed, 8 insertions(+), 5 deletions(-) + +diff --git a/src/libsystemd/sd-id128/sd-id128.c b/src/libsystemd/sd-id128/sd-id128.c +index e72af15..b194143 100644 +--- a/src/libsystemd/sd-id128/sd-id128.c ++++ b/src/libsystemd/sd-id128/sd-id128.c +@@ -88,7 +88,7 @@ _public_ int sd_id128_get_machine(sd_id128_t *ret) { + assert_return(ret, -EINVAL); + + if (sd_id128_is_null(saved_machine_id)) { +- r = id128_read("/etc/machine-id", ID128_PLAIN, &saved_machine_id); ++ r = id128_read(getenv("SYSTEMD_MACHINE_ID_PATH") ?: "/etc/machine-id", ID128_PLAIN, &saved_machine_id); + if (r < 0) + return r; + +diff --git a/src/test/test-fs-util.c b/src/test/test-fs-util.c +index e049abc..fef8515 100644 +--- a/src/test/test-fs-util.c ++++ b/src/test/test-fs-util.c +@@ -185,7 +185,7 @@ static void test_chase_symlinks(void) { + assert_se(streq(result, "/test-chase.fsldajfl")); + result = mfree(result); + +- r = chase_symlinks("/etc/machine-id/foo", NULL, 0, &result); ++ r = chase_symlinks("/etc/passwd/foo", NULL, 0, &result); + assert_se(r == -ENOTDIR); + result = mfree(result); + +@@ -258,23 +258,26 @@ static void test_chase_symlinks(void) { + assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL) >= 0); + } + +- p = strjoina(temp, "/machine-id-test"); +- assert_se(symlink("/usr/../etc/./machine-id", p) >= 0); ++ p = strjoina(temp, "/passwd-test"); ++ assert_se(symlink("/usr/../etc/./passwd", p) >= 0); + + pfd = chase_symlinks(p, NULL, CHASE_OPEN, NULL); + if (pfd != -ENOENT) { + _cleanup_close_ int fd = -1; ++/* + sd_id128_t a, b; ++*/ + + assert_se(pfd >= 0); + + fd = fd_reopen(pfd, O_RDONLY|O_CLOEXEC); + assert_se(fd >= 0); + safe_close(pfd); +- ++/* + assert_se(id128_read_fd(fd, ID128_PLAIN, &a) >= 0); + assert_se(sd_id128_get_machine(&b) >= 0); + assert_se(sd_id128_equal(a, b)); ++*/ + } + + /* Test CHASE_NOFOLLOW */ diff --git a/debian/patches/debian/Add-support-for-TuxOnIce-hibernation.patch b/debian/patches/debian/Add-support-for-TuxOnIce-hibernation.patch new file mode 100644 index 0000000..6ac1c00 --- /dev/null +++ b/debian/patches/debian/Add-support-for-TuxOnIce-hibernation.patch @@ -0,0 +1,30 @@ +From: Julien Muchembled <jm@jmuchemb.eu> +Date: Tue, 29 Apr 2014 11:40:50 +0200 +Subject: Add support for TuxOnIce hibernation + +systemd does not support non-mainline kernel features so upstream rejected this +patch. +It is however required for systemd integration by tuxonice-userui package. + +Forwarded: http://lists.freedesktop.org/archives/systemd-devel/2014-April/018960.html +--- + src/shared/sleep-config.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/src/shared/sleep-config.c b/src/shared/sleep-config.c +index 2e22bd0..b5050ea 100644 +--- a/src/shared/sleep-config.c ++++ b/src/shared/sleep-config.c +@@ -267,6 +267,12 @@ static bool enough_swap_for_hibernation(void) { + if (getenv_bool("SYSTEMD_BYPASS_HIBERNATION_MEMORY_CHECK") > 0) + return true; + ++ /* TuxOnIce is an alternate implementation for hibernation. ++ * It can be configured to compress the image to a file or an inactive ++ * swap partition, so there's nothing more we can do here. */ ++ if (access("/sys/power/tuxonice", F_OK) == 0) ++ return true; ++ + r = find_hibernate_location(NULL, NULL, &size, &used); + if (r < 0) + return false; diff --git a/debian/patches/debian/Bring-tmpfiles.d-tmp.conf-in-line-with-Debian-defaul.patch b/debian/patches/debian/Bring-tmpfiles.d-tmp.conf-in-line-with-Debian-defaul.patch new file mode 100644 index 0000000..085bafd --- /dev/null +++ b/debian/patches/debian/Bring-tmpfiles.d-tmp.conf-in-line-with-Debian-defaul.patch @@ -0,0 +1,24 @@ +From: Tollef Fog Heen <tfheen@err.no> +Date: Tue, 5 Jun 2012 20:59:36 +0200 +Subject: Bring tmpfiles.d/tmp.conf in line with Debian defaults + +Closes: #675422 +--- + tmpfiles.d/tmp.conf | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/tmpfiles.d/tmp.conf b/tmpfiles.d/tmp.conf +index 22555a0..8fb117f 100644 +--- a/tmpfiles.d/tmp.conf ++++ b/tmpfiles.d/tmp.conf +@@ -8,8 +8,8 @@ + # See tmpfiles.d(5) for details + + # Clear tmp directories separately, to make them easier to override +-q /tmp 1777 root root 10d +-q /var/tmp 1777 root root 30d ++D /tmp 1777 root root - ++#q /var/tmp 1777 root root 30d + + # Exclude namespace mountpoints created with PrivateTmp=yes + x /tmp/systemd-private-%b-* diff --git a/debian/patches/debian/Don-t-enable-audit-by-default.patch b/debian/patches/debian/Don-t-enable-audit-by-default.patch new file mode 100644 index 0000000..f58ce24 --- /dev/null +++ b/debian/patches/debian/Don-t-enable-audit-by-default.patch @@ -0,0 +1,30 @@ +From: Martin Pitt <martin.pitt@ubuntu.com> +Date: Sun, 28 Dec 2014 12:49:35 +0100 +Subject: Don't enable audit by default + +It causes flooding of dmesg and syslog, suppressing actually important +messages. + +Don't enable it for now, until a better solution is found: +http://lists.freedesktop.org/archives/systemd-devel/2014-December/026591.html + +Bug-Debian: https://bugs.debian.org/773528 +--- + src/journal/journald-audit.c | 5 ----- + 1 file changed, 5 deletions(-) + +diff --git a/src/journal/journald-audit.c b/src/journal/journald-audit.c +index accbad4..e62b1ee 100644 +--- a/src/journal/journald-audit.c ++++ b/src/journal/journald-audit.c +@@ -536,10 +536,5 @@ int server_open_audit(Server *s) { + if (r < 0) + return log_error_errno(r, "Failed to add audit fd to event loop: %m"); + +- /* We are listening now, try to enable audit */ +- r = enable_audit(s->audit_fd, true); +- if (r < 0) +- log_warning_errno(r, "Failed to issue audit enable call: %m"); +- + return 0; + } diff --git a/debian/patches/debian/Drop-seccomp-system-call-filter-for-udev.patch b/debian/patches/debian/Drop-seccomp-system-call-filter-for-udev.patch new file mode 100644 index 0000000..3ac8c83 --- /dev/null +++ b/debian/patches/debian/Drop-seccomp-system-call-filter-for-udev.patch @@ -0,0 +1,31 @@ +From: Michael Biebl <biebl@debian.org> +Date: Wed, 18 Jul 2018 23:49:16 +0200 +Subject: Drop seccomp system call filter for udev + +The seccomp based system call whitelist requires at least systemd 239 to +be the active init and during a dist-upgrade we can't guarantee that +systemd has been fully configured before udev is restarted. + +This partially reverts upstream commit +ee8f26180d01e3ddd4e5f20b03b81e5e737657ae. + +Once buster is released, this patch can be dropped. + +Closes: #903224 +--- + units/systemd-udevd.service.in | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/units/systemd-udevd.service.in b/units/systemd-udevd.service.in +index 6a3814e..2b9fa69 100644 +--- a/units/systemd-udevd.service.in ++++ b/units/systemd-udevd.service.in +@@ -29,8 +29,6 @@ PrivateMounts=yes + MemoryDenyWriteExecute=yes + RestrictRealtime=yes + RestrictAddressFamilies=AF_UNIX AF_NETLINK AF_INET AF_INET6 +-SystemCallFilter=@system-service @module @raw-io +-SystemCallErrorNumber=EPERM + SystemCallArchitectures=native + LockPersonality=yes + IPAddressDeny=any diff --git a/debian/patches/debian/Let-graphical-session-pre.target-be-manually-started.patch b/debian/patches/debian/Let-graphical-session-pre.target-be-manually-started.patch new file mode 100644 index 0000000..d48d61c --- /dev/null +++ b/debian/patches/debian/Let-graphical-session-pre.target-be-manually-started.patch @@ -0,0 +1,22 @@ +From: Iain Lane <iain@orangesquash.org.uk> +Date: Mon, 22 Aug 2016 07:03:27 +0200 +Subject: Let graphical-session-pre.target be manually started + +This is needed until https://github.com/systemd/systemd/issues/3750 is fixed. + +Forwarded: not-needed +Bug-Ubuntu: https://launchpad.net/bugs/1615341 +--- + units/user/graphical-session-pre.target | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/units/user/graphical-session-pre.target b/units/user/graphical-session-pre.target +index 3adfc5a..c4e1001 100644 +--- a/units/user/graphical-session-pre.target ++++ b/units/user/graphical-session-pre.target +@@ -12,5 +12,4 @@ Description=Session services which should run early before the graphical session + Documentation=man:systemd.special(7) + Requires=basic.target + Before=graphical-session.target +-RefuseManualStart=yes + StopWhenUnneeded=yes diff --git a/debian/patches/debian/Make-run-lock-tmpfs-an-API-fs.patch b/debian/patches/debian/Make-run-lock-tmpfs-an-API-fs.patch new file mode 100644 index 0000000..f53f723 --- /dev/null +++ b/debian/patches/debian/Make-run-lock-tmpfs-an-API-fs.patch @@ -0,0 +1,42 @@ +From: Michael Biebl <biebl@debian.org> +Date: Fri, 5 Sep 2014 01:15:16 +0200 +Subject: Make /run/lock tmpfs an API fs + +The /run/lock directory is world-writable in Debian due to historic +reasons. To avoid user processes filling up /run, we mount a separate +tmpfs for /run/lock. As this directory needs to be available during +early boot, we make it an API fs. + +Drop it from tmpfiles.d/legacy.conf to not clobber the permissions. + +Closes: #751392 +--- + src/core/mount-setup.c | 2 ++ + tmpfiles.d/legacy.conf | 1 - + 2 files changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/core/mount-setup.c b/src/core/mount-setup.c +index 3ce6164..3aae4c8 100644 +--- a/src/core/mount-setup.c ++++ b/src/core/mount-setup.c +@@ -83,6 +83,8 @@ static const MountPoint mount_table[] = { + #endif + { "tmpfs", "/run", "tmpfs", "mode=755", MS_NOSUID|MS_NODEV|MS_STRICTATIME, + NULL, MNT_FATAL|MNT_IN_CONTAINER }, ++ { "tmpfs", "/run/lock", "tmpfs", "mode=1777,size=5242880", MS_NOSUID|MS_NODEV|MS_NOEXEC, ++ NULL, MNT_FATAL|MNT_IN_CONTAINER }, + { "cgroup2", "/sys/fs/cgroup", "cgroup2", "nsdelegate", MS_NOSUID|MS_NOEXEC|MS_NODEV, + cg_is_unified_wanted, MNT_IN_CONTAINER|MNT_CHECK_WRITABLE }, + { "cgroup2", "/sys/fs/cgroup", "cgroup2", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, +diff --git a/tmpfiles.d/legacy.conf b/tmpfiles.d/legacy.conf +index 62e2ae0..ea5e735 100644 +--- a/tmpfiles.d/legacy.conf ++++ b/tmpfiles.d/legacy.conf +@@ -10,7 +10,6 @@ + # These files are considered legacy and are unnecessary on legacy-free + # systems. + +-d /run/lock 0755 root root - + L /var/lock - - - - ../run/lock + + # /run/lock/subsys is used for serializing SysV service execution, and diff --git a/debian/patches/debian/Only-start-logind-if-dbus-is-installed.patch b/debian/patches/debian/Only-start-logind-if-dbus-is-installed.patch new file mode 100644 index 0000000..7b1103e --- /dev/null +++ b/debian/patches/debian/Only-start-logind-if-dbus-is-installed.patch @@ -0,0 +1,24 @@ +From: Martin Pitt <martin.pitt@ubuntu.com> +Date: Mon, 9 Feb 2015 10:53:43 +0100 +Subject: Only start logind if dbus is installed + +logind fails to start in environments without dbus, such as LXC containers or +servers. Add a startup condition to avoid the very noisy startup failure. + +Part of #772700 +--- + units/systemd-logind.service.in | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/units/systemd-logind.service.in b/units/systemd-logind.service.in +index 38a7f26..16f1d9d 100644 +--- a/units/systemd-logind.service.in ++++ b/units/systemd-logind.service.in +@@ -14,6 +14,7 @@ Documentation=https://www.freedesktop.org/wiki/Software/systemd/logind + Documentation=https://www.freedesktop.org/wiki/Software/systemd/multiseat + Wants=user.slice + After=nss-user-lookup.target user.slice ++ConditionPathExists=/lib/systemd/system/dbus.service + + # Ask for the dbus socket. + Wants=dbus.socket diff --git a/debian/patches/debian/Re-enable-journal-forwarding-to-syslog.patch b/debian/patches/debian/Re-enable-journal-forwarding-to-syslog.patch new file mode 100644 index 0000000..78c2d01 --- /dev/null +++ b/debian/patches/debian/Re-enable-journal-forwarding-to-syslog.patch @@ -0,0 +1,56 @@ +From: Martin Pitt <martin.pitt@ubuntu.com> +Date: Fri, 28 Nov 2014 14:43:25 +0100 +Subject: Re-enable journal forwarding to syslog + +Revert upstream commit 46b131574fdd7d77 for now, until Debian's sysloggers +can/do all read from the journal directly. See + + http://lists.freedesktop.org/archives/systemd-devel/2014-November/025550.html + +for details. Once we grow a journal.conf.d/ directory, sysloggers can be moved +to pulling from the journal one by one and disable forwarding again in such a +conf.d snippet. +--- + man/journald.conf.xml | 2 +- + src/journal/journald-server.c | 1 + + src/journal/journald.conf | 2 +- + 3 files changed, 3 insertions(+), 2 deletions(-) + +diff --git a/man/journald.conf.xml b/man/journald.conf.xml +index 2791678..3a9e20a 100644 +--- a/man/journald.conf.xml ++++ b/man/journald.conf.xml +@@ -296,7 +296,7 @@ + the system console, or sent as wall messages to all logged-in users. These + options take boolean arguments. If forwarding to syslog is enabled but nothing + reads messages from the socket, forwarding to syslog has no effect. By default, +- only forwarding to wall is enabled. These settings may be overridden at boot time ++ only forwarding to syslog and wall is enabled. These settings may be overridden at boot time + with the kernel command line options + <literal>systemd.journald.forward_to_syslog</literal>, + <literal>systemd.journald.forward_to_kmsg</literal>, +diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c +index ba0b35d..cd45212 100644 +--- a/src/journal/journald-server.c ++++ b/src/journal/journald-server.c +@@ -1835,6 +1835,7 @@ int server_init(Server *s) { + s->rate_limit_interval = DEFAULT_RATE_LIMIT_INTERVAL; + s->rate_limit_burst = DEFAULT_RATE_LIMIT_BURST; + ++ s->forward_to_syslog = true; + s->forward_to_wall = true; + + s->max_file_usec = DEFAULT_MAX_FILE_USEC; +diff --git a/src/journal/journald.conf b/src/journal/journald.conf +index 2f1c661..8951d9e 100644 +--- a/src/journal/journald.conf ++++ b/src/journal/journald.conf +@@ -29,7 +29,7 @@ + #RuntimeMaxFiles=100 + #MaxRetentionSec= + #MaxFileSec=1month +-#ForwardToSyslog=no ++#ForwardToSyslog=yes + #ForwardToKMsg=no + #ForwardToConsole=no + #ForwardToWall=yes diff --git a/debian/patches/debian/Revert-core-enable-TasksMax-for-all-services-by-default-a.patch b/debian/patches/debian/Revert-core-enable-TasksMax-for-all-services-by-default-a.patch new file mode 100644 index 0000000..b4e4027 --- /dev/null +++ b/debian/patches/debian/Revert-core-enable-TasksMax-for-all-services-by-default-a.patch @@ -0,0 +1,56 @@ +From: Martin Pitt <martin.pitt@ubuntu.com> +Date: Mon, 9 May 2016 21:24:38 +0200 +Subject: Revert "core: enable TasksMax= for all services by default, + and set it to 512" + +This reverts commit 9ded9cd14cc03c67291b10a5c42ce5094ba0912f. + +Introducing a default limit on number of threads broke a lot of software which +regularly needs more, such as MySQL and RabbitMQ, or services that spawn off an +indefinite number of subtasks that are not in a scope, like LXC or cron. + +15% is way too much for most "simple" services, and it's too little for others +such as the ones mentioned above. There is also no particular rationale about +any particular global limit, so even if we'd bump it higher we'd just make the +limit even less useful while still breaking software. + +It is both much safer and also much more effective in terms of guarding against +berserk programs/bugs/unintended fork bombs etc. to set limits in units +individually. Once someone looks at one, this is then a great time to also flip +on the other resource and privilege limitations that systemd offers. + +Bug: https://github.com/systemd/systemd/issues/3211 +Bug-Debian: https://bugs.debian.org/823530 +Bug-Ubuntu: https://launchpad.net/bugs/1578080 +--- + man/systemd-system.conf.xml | 3 +-- + src/core/system.conf.in | 2 +- + 2 files changed, 2 insertions(+), 3 deletions(-) + +diff --git a/man/systemd-system.conf.xml b/man/systemd-system.conf.xml +index 27242b3..9ff7cc5 100644 +--- a/man/systemd-system.conf.xml ++++ b/man/systemd-system.conf.xml +@@ -320,8 +320,7 @@ + <listitem><para>Configure the default value for the per-unit <varname>TasksMax=</varname> setting. See + <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry> + for details. This setting applies to all unit types that support resource control settings, with the exception +- of slice units. Defaults to 15%, which equals 4915 with the kernel's defaults on the host, but might be smaller +- in OS containers.</para></listitem> ++ of slice units.</para></listitem> + </varlistentry> + + <varlistentry> +diff --git a/src/core/system.conf.in b/src/core/system.conf.in +index 0a58737..97ecd75 100644 +--- a/src/core/system.conf.in ++++ b/src/core/system.conf.in +@@ -45,7 +45,7 @@ + #DefaultBlockIOAccounting=no + #DefaultMemoryAccounting=@MEMORY_ACCOUNTING_DEFAULT@ + #DefaultTasksAccounting=yes +-#DefaultTasksMax=15% ++#DefaultTasksMax= + #DefaultLimitCPU= + #DefaultLimitFSIZE= + #DefaultLimitDATA= diff --git a/debian/patches/debian/Revert-core-one-step-back-again-for-nspawn-we-actual.patch b/debian/patches/debian/Revert-core-one-step-back-again-for-nspawn-we-actual.patch new file mode 100644 index 0000000..7c1261e --- /dev/null +++ b/debian/patches/debian/Revert-core-one-step-back-again-for-nspawn-we-actual.patch @@ -0,0 +1,37 @@ +From: Martin Pitt <martin.pitt@ubuntu.com> +Date: Mon, 27 Apr 2015 15:29:13 +0200 +Subject: Revert "core: one step back again, + for nspawn we actually can't wait for cgroups running empty since systemd + will get exactly zero notifications about it" + +This reverts commit 743970d2ea6d08aa7c7bff8220f6b7702f2b1db7. + +Bug-Debian: https://bugs.debian.org/784720 +Bug-Ubuntu: https://launchpad.net/bugs/1448259 +Bug-Fedora: https://bugzilla.redhat.com/show_bug.cgi?id=1141137 +--- + src/core/unit.c | 11 +---------- + 1 file changed, 1 insertion(+), 10 deletions(-) + +diff --git a/src/core/unit.c b/src/core/unit.c +index 2a7359a..d55aba8 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -4553,16 +4553,7 @@ int unit_kill_context( + + } else if (r > 0) { + +- /* FIXME: For now, on the legacy hierarchy, we will not wait for the cgroup members to die if +- * we are running in a container or if this is a delegation unit, simply because cgroup +- * notification is unreliable in these cases. It doesn't work at all in containers, and outside +- * of containers it can be confused easily by left-over directories in the cgroup — which +- * however should not exist in non-delegated units. On the unified hierarchy that's different, +- * there we get proper events. Hence rely on them. */ +- +- if (cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER) > 0 || +- (detect_container() == 0 && !unit_cgroup_delegate(u))) +- wait_for_exit = true; ++ wait_for_exit = true; + + if (send_sighup) { + set_free(pid_set); diff --git a/debian/patches/debian/Revert-core-set-RLIMIT_CORE-to-unlimited-by-default.patch b/debian/patches/debian/Revert-core-set-RLIMIT_CORE-to-unlimited-by-default.patch new file mode 100644 index 0000000..9e1ab13 --- /dev/null +++ b/debian/patches/debian/Revert-core-set-RLIMIT_CORE-to-unlimited-by-default.patch @@ -0,0 +1,43 @@ +From: Martin Pitt <martin.pitt@ubuntu.com> +Date: Sat, 27 Feb 2016 12:27:06 +0100 +Subject: Revert "core: set RLIMIT_CORE to unlimited by default" + +Partially revert commit 15a900327ab as this completely breaks core dumps +without systemd-coredump. It's also contradicting core(8), and it's not +systemd's place to redefine the kernel definitions of core files. + +Commit bdfd7b2c now honours the process' RLIMIT_CORE for systemd-coredump. This +isn't what RLIMIT_CORE is supposed to do (it limits the size of the core +*file*, but the kernel deliberately ignores it for piping), so set a static +2^63 core size limit for systemd-coredump to go back to the previous behaviour +(otherwise the change above would break systemd-coredump). + +Bug-Debian: https://bugs.debian.org/815020 +--- + src/core/main.c | 2 -- + sysctl.d/50-coredump.conf.in | 2 +- + 2 files changed, 1 insertion(+), 3 deletions(-) + +diff --git a/src/core/main.c b/src/core/main.c +index 255e204..7f8dfe4 100644 +--- a/src/core/main.c ++++ b/src/core/main.c +@@ -2459,8 +2459,6 @@ int main(int argc, char *argv[]) { + kernel_timestamp = DUAL_TIMESTAMP_NULL; + } + +- initialize_coredump(skip_setup); +- + r = fixup_environment(); + if (r < 0) { + log_emergency_errno(r, "Failed to fix up PID 1 environment: %m"); +diff --git a/sysctl.d/50-coredump.conf.in b/sysctl.d/50-coredump.conf.in +index ccd5c2c..53e74a1 100644 +--- a/sysctl.d/50-coredump.conf.in ++++ b/sysctl.d/50-coredump.conf.in +@@ -9,4 +9,4 @@ + # and systemd-coredump(8) and core(5) for the explanation of the + # setting below. + +-kernel.core_pattern=|@rootlibexecdir@/systemd-coredump %P %u %g %s %t %c %h %e ++kernel.core_pattern=|@rootlibexecdir@/systemd-coredump %P %u %g %s %t 9223372036854775808 %h %e diff --git a/debian/patches/debian/Revert-udev-network-device-renaming-immediately-give.patch b/debian/patches/debian/Revert-udev-network-device-renaming-immediately-give.patch new file mode 100644 index 0000000..acd6fbd --- /dev/null +++ b/debian/patches/debian/Revert-udev-network-device-renaming-immediately-give.patch @@ -0,0 +1,89 @@ +From: Michael Biebl <biebl@debian.org> +Date: Thu, 18 Jul 2013 01:04:07 +0200 +Subject: Revert "udev: network device renaming - immediately give up if the + target name isn't available" + +This reverts commit 97595710b77aa162ca5e20da57d0a1ed7355eaad. + +We need to keep supporting systems with 75-persistent-net-generator.rules +generated names for a while after switching to net.ifnames. Re-apply this old +hack to make the renaming less likely to fail. +--- + src/udev/udev-event.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 46 insertions(+), 5 deletions(-) + +diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c +index faec4fc..0b295b8 100644 +--- a/src/udev/udev-event.c ++++ b/src/udev/udev-event.c +@@ -680,6 +680,7 @@ static int rename_netif(UdevEvent *event) { + const char *action, *oldname; + char name[IFNAMSIZ]; + int ifindex, r; ++ int loop; + + if (!event->name) + return 0; /* No new name is requested. */ +@@ -705,17 +706,57 @@ static int rename_netif(UdevEvent *event) { + return log_device_error_errno(dev, r, "Failed to get ifindex: %m"); + + strscpy(name, IFNAMSIZ, event->name); ++ + r = rtnl_set_link_name(&event->rtnl, ifindex, name); +- if (r < 0) +- return log_device_error_errno(dev, r, "Failed to rename network interface %i from '%s' to '%s': %m", ifindex, oldname, name); ++ if (r >= 0) { ++ r = device_rename(dev, event->name); ++ if (r < 0) ++ return log_warning_errno(r, "Network interface %i is renamed from '%s' to '%s', but could not update sd_device object: %m", ifindex, oldname, name); ++ ++ log_device_debug(dev, "Network interface %i is renamed from '%s' to '%s'", ifindex, oldname, name); ++ ++ return 1; ++ } ++ ++ /* keep trying if the destination interface name already exists */ ++ if (r != -EEXIST) ++ goto out; + +- r = device_rename(dev, event->name); ++ /* free our own name, another process may wait for us */ ++ snprintf(name, IFNAMSIZ, "rename%u", ifindex); ++ r = rtnl_set_link_name(&event->rtnl, ifindex, name); + if (r < 0) +- return log_warning_errno(r, "Network interface %i is renamed from '%s' to '%s', but could not update sd_device object: %m", ifindex, oldname, name); ++ goto out; + ++ /* log temporary name */ + log_device_debug(dev, "Network interface %i is renamed from '%s' to '%s'", ifindex, oldname, name); + +- return 1; ++ /* wait a maximum of 90 seconds for our target to become available */ ++ strscpy(name, IFNAMSIZ, event->name); ++ loop = 90 * 20; ++ while (loop--) { ++ const struct timespec duration = { 0, 1000 * 1000 * 1000 / 20 }; ++ ++ nanosleep(&duration, NULL); ++ ++ r = rtnl_set_link_name(&event->rtnl, ifindex, name); ++ if (r >= 0) { ++ r = device_rename(dev, event->name); ++ if (r < 0) ++ return log_warning_errno(r, "Network interface %i is renamed from '%s' to '%s', but could not update sd_device object: %m", ifindex, oldname, name); ++ ++ log_device_debug(dev, "Network interface %i is renamed from '%s' to '%s'", ifindex, oldname, name); ++ ++ return 1; ++ } ++ if (r != -EEXIST) ++ goto out; ++ } ++ ++out: ++ if (r < 0) ++ return log_device_error_errno(dev, r, "Failed to rename network interface %i from '%s' to '%s': %m", ifindex, oldname, name); ++ return r; + } + + static int update_devnode(UdevEvent *event) { diff --git a/debian/patches/debian/Skip-filesystem-check-if-already-done-by-the-initram.patch b/debian/patches/debian/Skip-filesystem-check-if-already-done-by-the-initram.patch new file mode 100644 index 0000000..d844cbe --- /dev/null +++ b/debian/patches/debian/Skip-filesystem-check-if-already-done-by-the-initram.patch @@ -0,0 +1,57 @@ +From: Nis Martensen <nis.martensen@web.de> +Date: Tue, 19 Jan 2016 22:01:43 +0100 +Subject: Skip filesystem check if already done by the initramfs + +Newer versions of initramfs-tools already fsck and mount / and /usr in +the initramfs. Skip the filesystem check in this case. + +Based on a previous patch by Michael Biebl <biebl@debian.org>. + +Closes: #782522 +Closes: #810748 +--- + src/fstab-generator/fstab-generator.c | 11 ++++++++--- + units/systemd-fsck-root.service.in | 1 + + 2 files changed, 9 insertions(+), 3 deletions(-) + +diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c +index 55a8242..777ae5f 100644 +--- a/src/fstab-generator/fstab-generator.c ++++ b/src/fstab-generator/fstab-generator.c +@@ -310,6 +310,7 @@ static int add_mount( + *where_escaped = NULL; + _cleanup_fclose_ FILE *f = NULL; + int r; ++ struct stat sb; + + assert(what); + assert(where); +@@ -387,9 +388,13 @@ static int add_mount( + } + + if (passno != 0) { +- r = generator_write_fsck_deps(f, dest, what, where, fstype); +- if (r < 0) +- return r; ++ if (streq(where, "/usr") && stat("/run/initramfs/fsck-usr", &sb) == 0) ++ ; /* skip /usr fsck if it has already been checked in the initramfs */ ++ else { ++ r = generator_write_fsck_deps(f, dest, what, where, fstype); ++ if (r < 0) ++ return r; ++ } + } + + fprintf(f, "\n[Mount]\n"); +diff --git a/units/systemd-fsck-root.service.in b/units/systemd-fsck-root.service.in +index bea6c16..49df031 100644 +--- a/units/systemd-fsck-root.service.in ++++ b/units/systemd-fsck-root.service.in +@@ -16,6 +16,7 @@ Before=local-fs.target shutdown.target + Wants=systemd-fsckd.socket + After=systemd-fsckd.socket + ConditionPathIsReadWrite=!/ ++ConditionPathExists=!/run/initramfs/fsck-root + + [Service] + Type=oneshot diff --git a/debian/patches/debian/Use-Debian-specific-config-files.patch b/debian/patches/debian/Use-Debian-specific-config-files.patch new file mode 100644 index 0000000..1ad2608 --- /dev/null +++ b/debian/patches/debian/Use-Debian-specific-config-files.patch @@ -0,0 +1,428 @@ +From: Michael Biebl <biebl@debian.org> +Date: Thu, 18 Jul 2013 20:11:02 +0200 +Subject: Use Debian specific config files + +Use /etc/default/locale instead of /etc/locale.conf for locale settings. + +Use /etc/default/keyboard instead of /etc/X11/xorg.conf.d/00-keyboard.conf for +keyboard configuration. + +Read/write /etc/timezone if /etc/localtime does not exist. +--- + src/basic/time-util.c | 21 ++++- + src/core/locale-setup.c | 21 +++++ + src/locale/keymap-util.c | 209 +++++++++++++++++++++++------------------------ + src/timedate/timedated.c | 10 +++ + 4 files changed, 154 insertions(+), 107 deletions(-) + +diff --git a/src/basic/time-util.c b/src/basic/time-util.c +index 62cdc30..d66f506 100644 +--- a/src/basic/time-util.c ++++ b/src/basic/time-util.c +@@ -1381,8 +1381,25 @@ int get_timezone(char **tz) { + int r; + + r = readlink_malloc("/etc/localtime", &t); +- if (r < 0) +- return r; /* returns EINVAL if not a symlink */ ++ if (r < 0) { ++ if (r != -EINVAL) ++ return r; /* returns EINVAL if not a symlink */ ++ ++ r = read_one_line_file("/etc/timezone", &t); ++ if (r < 0) { ++ if (r != -ENOENT) ++ log_warning_errno(r, "Failed to read /etc/timezone: %m"); ++ return -EINVAL; ++ } ++ ++ if (!timezone_is_valid(t, LOG_DEBUG)) ++ return -EINVAL; ++ z = strdup(t); ++ if (!z) ++ return -ENOMEM; ++ *tz = z; ++ return 0; ++ } + + e = PATH_STARTSWITH_SET(t, "/usr/share/zoneinfo/", "../usr/share/zoneinfo/"); + if (!e) +diff --git a/src/core/locale-setup.c b/src/core/locale-setup.c +index aa4a89c..8f36bbe 100644 +--- a/src/core/locale-setup.c ++++ b/src/core/locale-setup.c +@@ -59,6 +59,27 @@ int locale_setup(char ***environment) { + log_warning_errno(r, "Failed to read /etc/locale.conf: %m"); + } + ++ if (r <= 0) { ++ r = parse_env_file(NULL, "/etc/default/locale", ++ "LANG", &variables[VARIABLE_LANG], ++ "LANGUAGE", &variables[VARIABLE_LANGUAGE], ++ "LC_CTYPE", &variables[VARIABLE_LC_CTYPE], ++ "LC_NUMERIC", &variables[VARIABLE_LC_NUMERIC], ++ "LC_TIME", &variables[VARIABLE_LC_TIME], ++ "LC_COLLATE", &variables[VARIABLE_LC_COLLATE], ++ "LC_MONETARY", &variables[VARIABLE_LC_MONETARY], ++ "LC_MESSAGES", &variables[VARIABLE_LC_MESSAGES], ++ "LC_PAPER", &variables[VARIABLE_LC_PAPER], ++ "LC_NAME", &variables[VARIABLE_LC_NAME], ++ "LC_ADDRESS", &variables[VARIABLE_LC_ADDRESS], ++ "LC_TELEPHONE", &variables[VARIABLE_LC_TELEPHONE], ++ "LC_MEASUREMENT", &variables[VARIABLE_LC_MEASUREMENT], ++ "LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION]); ++ ++ if (r < 0 && r != -ENOENT) ++ log_warning_errno(r, "Failed to read /etc/default/locale: %m"); ++ } ++ + for (i = 0; i < _VARIABLE_LC_MAX; i++) { + char *s; + +diff --git a/src/locale/keymap-util.c b/src/locale/keymap-util.c +index c203c7a..f4ee123 100644 +--- a/src/locale/keymap-util.c ++++ b/src/locale/keymap-util.c +@@ -97,6 +97,7 @@ void locale_simplify(char *locale[_VARIABLE_LC_MAX]) { + int locale_read_data(Context *c, sd_bus_message *m) { + struct stat st; + int r; ++ const char *path = "/etc/locale.conf"; + + /* Do not try to re-read the file within single bus operation. */ + if (m) { +@@ -107,7 +108,11 @@ int locale_read_data(Context *c, sd_bus_message *m) { + c->locale_cache = sd_bus_message_ref(m); + } + +- r = stat("/etc/locale.conf", &st); ++ r = stat(path, &st); ++ if (r < 0 && errno == ENOENT) { ++ path = "/etc/default/locale"; ++ r = stat(path, &st); ++ } + if (r < 0 && errno != ENOENT) + return -errno; + +@@ -122,7 +127,7 @@ int locale_read_data(Context *c, sd_bus_message *m) { + c->locale_mtime = t; + context_free_locale(c); + +- r = parse_env_file(NULL, "/etc/locale.conf", ++ r = parse_env_file(NULL, path, + "LANG", &c->locale[VARIABLE_LANG], + "LANGUAGE", &c->locale[VARIABLE_LANGUAGE], + "LC_CTYPE", &c->locale[VARIABLE_LC_CTYPE], +@@ -203,8 +208,6 @@ int vconsole_read_data(Context *c, sd_bus_message *m) { + } + + int x11_read_data(Context *c, sd_bus_message *m) { +- _cleanup_fclose_ FILE *f = NULL; +- bool in_section = false; + struct stat st; + usec_t t; + int r; +@@ -218,7 +221,7 @@ int x11_read_data(Context *c, sd_bus_message *m) { + c->x11_cache = sd_bus_message_ref(m); + } + +- if (stat("/etc/X11/xorg.conf.d/00-keyboard.conf", &st) < 0) { ++ if (stat("/etc/default/keyboard", &st) < 0) { + if (errno != ENOENT) + return -errno; + +@@ -235,61 +238,14 @@ int x11_read_data(Context *c, sd_bus_message *m) { + c->x11_mtime = t; + context_free_x11(c); + +- f = fopen("/etc/X11/xorg.conf.d/00-keyboard.conf", "re"); +- if (!f) +- return -errno; +- +- for (;;) { +- _cleanup_free_ char *line = NULL; +- char *l; +- +- r = read_line(f, LONG_LINE_MAX, &line); +- if (r < 0) +- return r; +- if (r == 0) +- break; +- +- l = strstrip(line); +- if (IN_SET(l[0], 0, '#')) +- continue; +- +- if (in_section && first_word(l, "Option")) { +- _cleanup_strv_free_ char **a = NULL; +- +- r = strv_split_extract(&a, l, WHITESPACE, EXTRACT_QUOTES); +- if (r < 0) +- return r; +- +- if (strv_length(a) == 3) { +- char **p = NULL; +- +- if (streq(a[1], "XkbLayout")) +- p = &c->x11_layout; +- else if (streq(a[1], "XkbModel")) +- p = &c->x11_model; +- else if (streq(a[1], "XkbVariant")) +- p = &c->x11_variant; +- else if (streq(a[1], "XkbOptions")) +- p = &c->x11_options; +- +- if (p) { +- free_and_replace(*p, a[2]); +- } +- } ++ r = parse_env_file(NULL, "/etc/default/keyboard", ++ "XKBMODEL", &c->x11_model, ++ "XKBLAYOUT", &c->x11_layout, ++ "XKBVARIANT", &c->x11_variant, ++ "XKBOPTIONS", &c->x11_options); + +- } else if (!in_section && first_word(l, "Section")) { +- _cleanup_strv_free_ char **a = NULL; +- +- r = strv_split_extract(&a, l, WHITESPACE, EXTRACT_QUOTES); +- if (r < 0) +- return -ENOMEM; +- +- if (strv_length(a) == 2 && streq(a[1], "InputClass")) +- in_section = true; +- +- } else if (in_section && first_word(l, "EndSection")) +- in_section = false; +- } ++ if (r < 0) ++ return r; + + return 0; + } +@@ -298,9 +254,18 @@ int locale_write_data(Context *c, char ***settings) { + _cleanup_strv_free_ char **l = NULL; + struct stat st; + int r, p; ++ const char *path = "/etc/locale.conf"; + + /* Set values will be returned as strv in *settings on success. */ + ++ r = load_env_file(NULL, path, &l); ++ if (r < 0 && r == -ENOENT) { ++ path = "/etc/default/locale"; ++ r = load_env_file(NULL, path, &l); ++ } ++ if (r < 0 && r != -ENOENT) ++ return r; ++ + for (p = 0; p < _VARIABLE_LC_MAX; p++) { + _cleanup_free_ char *t = NULL; + char **u; +@@ -323,20 +288,20 @@ int locale_write_data(Context *c, char ***settings) { + } + + if (strv_isempty(l)) { +- if (unlink("/etc/locale.conf") < 0) ++ if (unlink(path) < 0) + return errno == ENOENT ? 0 : -errno; + + c->locale_mtime = USEC_INFINITY; + return 0; + } + +- r = write_env_file_label("/etc/locale.conf", l); ++ r = write_env_file_label(path, l); + if (r < 0) + return r; + + *settings = TAKE_PTR(l); + +- if (stat("/etc/locale.conf", &st) >= 0) ++ if (stat(path, &st) >= 0) + c->locale_mtime = timespec_load(&st.st_mtim); + + return 0; +@@ -404,70 +369,104 @@ int vconsole_write_data(Context *c) { + } + + int x11_write_data(Context *c) { +- _cleanup_fclose_ FILE *f = NULL; +- _cleanup_free_ char *temp_path = NULL; + struct stat st; + int r; ++ char *t, **u, **l = NULL; + +- if (isempty(c->x11_layout) && +- isempty(c->x11_model) && +- isempty(c->x11_variant) && +- isempty(c->x11_options)) { ++ r = load_env_file(NULL, "/etc/default/keyboard", &l); ++ if (r < 0 && r != -ENOENT) ++ return r; + +- if (unlink("/etc/X11/xorg.conf.d/00-keyboard.conf") < 0) +- return errno == ENOENT ? 0 : -errno; ++ /* This could perhaps be done more elegantly using an array ++ * like we do for the locale, instead of struct ++ */ ++ if (isempty(c->x11_layout)) { ++ l = strv_env_unset(l, "XKBLAYOUT"); ++ } else { ++ if (asprintf(&t, "XKBLAYOUT=%s", c->x11_layout) < 0) { ++ strv_free(l); ++ return -ENOMEM; ++ } + +- c->vc_mtime = USEC_INFINITY; +- return 0; ++ u = strv_env_set(l, t); ++ free(t); ++ strv_free(l); ++ ++ if (!u) ++ return -ENOMEM; ++ ++ l = u; + } + +- mkdir_p_label("/etc/X11/xorg.conf.d", 0755); ++ if (isempty(c->x11_model)) { ++ l = strv_env_unset(l, "XKBMODEL"); ++ } else { ++ if (asprintf(&t, "XKBMODEL=%s", c->x11_model) < 0) { ++ strv_free(l); ++ return -ENOMEM; ++ } ++ ++ u = strv_env_set(l, t); ++ free(t); ++ strv_free(l); + +- r = fopen_temporary("/etc/X11/xorg.conf.d/00-keyboard.conf", &f, &temp_path); +- if (r < 0) +- return r; ++ if (!u) ++ return -ENOMEM; + +- (void) __fsetlocking(f, FSETLOCKING_BYCALLER); +- (void) fchmod(fileno(f), 0644); ++ l = u; ++ } + +- fputs("# Written by systemd-localed(8), read by systemd-localed and Xorg. It's\n" +- "# probably wise not to edit this file manually. Use localectl(1) to\n" +- "# instruct systemd-localed to update it.\n" +- "Section \"InputClass\"\n" +- " Identifier \"system-keyboard\"\n" +- " MatchIsKeyboard \"on\"\n", f); ++ if (isempty(c->x11_variant)) { ++ l = strv_env_unset(l, "XKBVARIANT"); ++ } else { ++ if (asprintf(&t, "XKBVARIANT=%s", c->x11_variant) < 0) { ++ strv_free(l); ++ return -ENOMEM; ++ } + +- if (!isempty(c->x11_layout)) +- fprintf(f, " Option \"XkbLayout\" \"%s\"\n", c->x11_layout); ++ u = strv_env_set(l, t); ++ free(t); ++ strv_free(l); + +- if (!isempty(c->x11_model)) +- fprintf(f, " Option \"XkbModel\" \"%s\"\n", c->x11_model); ++ if (!u) ++ return -ENOMEM; + +- if (!isempty(c->x11_variant)) +- fprintf(f, " Option \"XkbVariant\" \"%s\"\n", c->x11_variant); ++ l = u; ++ } + +- if (!isempty(c->x11_options)) +- fprintf(f, " Option \"XkbOptions\" \"%s\"\n", c->x11_options); ++ if (isempty(c->x11_options)) { ++ l = strv_env_unset(l, "XKBOPTIONS"); ++ } else { ++ if (asprintf(&t, "XKBOPTIONS=%s", c->x11_options) < 0) { ++ strv_free(l); ++ return -ENOMEM; ++ } + +- fputs("EndSection\n", f); ++ u = strv_env_set(l, t); ++ free(t); ++ strv_free(l); + +- r = fflush_sync_and_check(f); +- if (r < 0) +- goto fail; ++ if (!u) ++ return -ENOMEM; + +- if (rename(temp_path, "/etc/X11/xorg.conf.d/00-keyboard.conf") < 0) { +- r = -errno; +- goto fail; ++ l = u; + } + +- if (stat("/etc/X11/xorg.conf.d/00-keyboard.conf", &st) >= 0) +- c->x11_mtime = timespec_load(&st.st_mtim); ++ if (strv_isempty(l)) { ++ strv_free(l); + +- return 0; ++ if (unlink("/etc/default/keyboard") < 0) ++ return errno == ENOENT ? 0 : -errno; + +-fail: +- if (temp_path) +- (void) unlink(temp_path); ++ c->vc_mtime = USEC_INFINITY; ++ return 0; ++ } ++ ++ r = write_env_file("/etc/default/keyboard", l); ++ strv_free(l); ++ ++ if (r >= 0 && stat("/etc/default/keyboard", &st) >= 0) ++ c->x11_mtime = timespec_load(&st.st_mtim); + + return r; + } +diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c +index 398d4f4..d681d58 100644 +--- a/src/timedate/timedated.c ++++ b/src/timedate/timedated.c +@@ -215,6 +215,7 @@ static int context_read_data(Context *c) { + static int context_write_data_timezone(Context *c) { + _cleanup_free_ char *p = NULL; + int r = 0; ++ struct stat st; + + assert(c); + +@@ -222,6 +223,9 @@ static int context_write_data_timezone(Context *c) { + if (unlink("/etc/localtime") < 0 && errno != ENOENT) + r = -errno; + ++ if (unlink("/etc/timezone") < 0 && errno != ENOENT) ++ r = -errno; ++ + return r; + } + +@@ -233,6 +237,12 @@ static int context_write_data_timezone(Context *c) { + if (r < 0) + return r; + ++ if (stat("/etc/timezone", &st) == 0 && S_ISREG(st.st_mode)) { ++ r = write_string_file("/etc/timezone", c->zone, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC); ++ if (r < 0) ++ return r; ++ } ++ + return 0; + } + diff --git a/debian/patches/debian/fsckd-daemon-for-inter-fsckd-communication.patch b/debian/patches/debian/fsckd-daemon-for-inter-fsckd-communication.patch new file mode 100644 index 0000000..e4ca7b1 --- /dev/null +++ b/debian/patches/debian/fsckd-daemon-for-inter-fsckd-communication.patch @@ -0,0 +1,1055 @@ +From: Didier Roche <didrocks@ubuntu.com> +Date: Fri, 22 May 2015 13:04:38 +0200 +Subject: fsckd daemon for inter-fsckd communication + +Global logic: +Add systemd-fsckd multiplexer which accepts multiple (via systemd-fsck's +/run/systemd/fsck.progress socket) fsck instances to connect to it and sends +progress report. systemd-fsckd then computes and writes to /dev/console the +number of devices currently being checked and the minimum fsck progress. + +Plymouth and user interaction: +Forward the progress to plymouth and support canellation of in progress fsck. +Try to connect and send to plymouth (if running) some checked report progress, +using direct plymouth protocole. + +Update message is the following: +fsckd:<num_devices>:<progress>:<string> +* num_devices corresponds to the current number of devices being checked (int) +* progress corresponds to the current minimum percentage of all devices being + checked (float, from 0 to 100) +* string is a translated message ready to be displayed by the plymouth theme + displaying the information above. It can be overridden by plymouth themes + supporting i18n. + +Grab in fsckd plymouth watch key Control+C, and propagate this cancel request +to systemd-fsck which will terminate fsck. + +Send a message to signal to user what key we are grabbing for fsck cancel. + +Message is: fsckd-cancel-msg:<string> +Where string is a translated string ready to be displayed by the plymouth theme +indicating that Control+C can be used to cancel current checks. It can be +overridden (matching only fsckd-cancel-msg prefix) for themes supporting i18n. + +Misc: +systemd-fsckd stops on idle when no fsck is connected. +Add man page explaining the plymouth theme protocol, usage of the daemon +as well as the socket activation part. Adapt existing fsck man page. + +Note that fsckd had lived in the upstream tree for a while, but was removed. +More information at +http://lists.freedesktop.org/archives/systemd-devel/2015-April/030175.html +- +--- + man/rules/meson.build | 1 + + man/systemd-fsckd.service.xml | 162 +++++++++ + meson.build | 8 + + po/POTFILES.in | 1 + + src/fsckd/fsckd.c | 690 +++++++++++++++++++++++++++++++++++++ + units/meson.build | 2 + + units/systemd-fsck-root.service.in | 2 + + units/systemd-fsck@.service.in | 3 +- + units/systemd-fsckd.service.in | 17 + + units/systemd-fsckd.socket | 15 + + 10 files changed, 900 insertions(+), 1 deletion(-) + create mode 100644 man/systemd-fsckd.service.xml + create mode 100644 src/fsckd/fsckd.c + create mode 100644 units/systemd-fsckd.service.in + create mode 100644 units/systemd-fsckd.socket + +diff --git a/man/rules/meson.build b/man/rules/meson.build +index 0c990a0..dff5d2f 100644 +--- a/man/rules/meson.build ++++ b/man/rules/meson.build +@@ -657,6 +657,7 @@ manpages = [ + '8', + ['systemd-fsck', 'systemd-fsck-root.service'], + ''], ++ ['systemd-fsckd.service', '8', ['systemd-fsckd.socket', 'systemd-fsckd'], ''], + ['systemd-fstab-generator', '8', [], ''], + ['systemd-getty-generator', '8', [], ''], + ['systemd-gpt-auto-generator', '8', [], ''], +diff --git a/man/systemd-fsckd.service.xml b/man/systemd-fsckd.service.xml +new file mode 100644 +index 0000000..b7ad58d +--- /dev/null ++++ b/man/systemd-fsckd.service.xml +@@ -0,0 +1,162 @@ ++<?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"> ++<!-- ++ This file is part of systemd. ++ ++ Copyright 2015 Canonical ++ ++ systemd is free software; you can redistribute it and/or modify it ++ under the terms of the GNU Lesser General Public License as published by ++ the Free Software Foundation; either version 2.1 of the License, or ++ (at your option) any later version. ++ ++ systemd is distributed in the hope that it will be useful, but ++ WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public License ++ along with systemd; If not, see <http://www.gnu.org/licenses/>. ++--> ++<refentry id="systemd-fsckd.service" xmlns:xi="http://www.w3.org/2001/XInclude"> ++ ++ <refentryinfo> ++ <title>systemd-fsckd.service</title> ++ <productname>systemd</productname> ++ ++ <authorgroup> ++ <author> ++ <contrib>Developer</contrib> ++ <firstname>Didier</firstname> ++ <surname>Roche</surname> ++ <email>didrocks@ubuntu.com</email> ++ </author> ++ </authorgroup> ++ </refentryinfo> ++ ++ <refmeta> ++ <refentrytitle>systemd-fsckd.service</refentrytitle> ++ <manvolnum>8</manvolnum> ++ </refmeta> ++ ++ <refnamediv> ++ <refname>systemd-fsckd.service</refname> ++ <refname>systemd-fsckd.socket</refname> ++ <refname>systemd-fsckd</refname> ++ <refpurpose>File system check progress reporting</refpurpose> ++ </refnamediv> ++ ++ <refsynopsisdiv> ++ <para><filename>systemd-fsckd.service</filename></para> ++ <para><filename>systemd-fsckd.socket</filename></para> ++ <para><filename>/usr/lib/systemd/systemd-fsckd</filename></para> ++ </refsynopsisdiv> ++ ++ <refsect1> ++ <title>Description</title> ++ ++ <para><filename>systemd-fsckd.service</filename> is a service responsible ++ for receiving file system check progress, and communicating some ++ consolidated data to console and plymouth (if running). It also handles ++ possible check cancellations.</para> ++ ++ <para><command>systemd-fsckd</command> receives messages about file ++ system check progress from <command>fsck</command> through an ++ UNIX domain socket. It can display the progress of the least advanced ++ fsck as well as the total number of devices being checked in parallel ++ to the console. It will also send progress messages to plymouth. ++ Both the raw data and translated messages are sent, so compiled ++ plymouth themes can use the raw data to display custom messages, and ++ scripted themes, not supporting i18n, can display the translated ++ versions.</para> ++ ++ <para><command>systemd-fsckd</command> will instruct plymouth to grab ++ Control+C keypresses. When the key is pressed, running checks will be ++ terminated. It will also cancel any newly connected fsck instances for ++ the lifetime of <filename>systemd-fsckd</filename>.</para> ++ </refsect1> ++ ++ <refsect1> ++ <title>Protocol for communication with plymouth</title> ++ ++ <para><filename>systemd-fsckd</filename> passes the ++ following messages to the theme:</para> ++ ++ <para>Progress update, sent as a plymouth update message: ++ <literal>fsckd:<num_devices>:<progress>:<string></literal> ++ <variablelist> ++ <varlistentry> ++ <term><literal><num_devices></literal></term> ++ <listitem><para>the current number of devices ++ being checked (int)</para></listitem> ++ </varlistentry> ++ <varlistentry> ++ <term><literal><progress></literal></term> ++ <listitem><para>the current minimum percentage of ++ all devices being checking (float, from 0 to 100)</para></listitem> ++ </varlistentry> ++ <varlistentry> ++ <term><literal><string></literal></term> ++ <listitem><para>a translated message ready to be displayed ++ by the plymouth theme displaying the data above. It can be overridden ++ by themes supporting i18n.</para></listitem> ++ </varlistentry> ++ </variablelist> ++ </para> ++ ++ <para>Cancel message, sent as a traditional plymouth message: ++ <literal>fsckd-cancel-msg:<string></literal> ++ <variablelist> ++ <varlistentry> ++ <term><literal><strings></literal></term> ++ <listitem><para>a translated string ready to be displayed ++ by the plymouth theme indicating that Control+C can be used to cancel ++ current checks. It can be overridden (matching only ++ <literal>fsckd-cancel-msg</literal> prefix) ++ by themes supporting i18n.</para></listitem> ++ </varlistentry> ++ </variablelist> ++ </para> ++ </refsect1> ++ ++ <refsect1> ++ <title>Options</title> ++ ++ <para>The following options are understood:</para> ++ ++ <variablelist> ++ <xi:include href="standard-options.xml" xpointer="help" /> ++ <xi:include href="standard-options.xml" xpointer="version" /> ++ </variablelist> ++ ++ </refsect1> ++ ++ <refsect1> ++ <title>Exit status</title> ++ ++ <para>On success, 0 is returned, a non-zero failure ++ code otherwise. Note that the daemon stays idle for ++ a while to accept new <filename>fsck</filename> ++ connections before exiting.</para> ++ </refsect1> ++ ++ <refsect1> ++ <title>See Also</title> ++ <para> ++ <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>, ++ <citerefentry><refentrytitle>systemd-fsck</refentrytitle><manvolnum>8</manvolnum></citerefentry>, ++ <citerefentry project='man-pages'><refentrytitle>fsck</refentrytitle><manvolnum>8</manvolnum></citerefentry>, ++ <citerefentry><refentrytitle>systemd-quotacheck.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>, ++ <citerefentry project='man-pages'><refentrytitle>fsck.btrfs</refentrytitle><manvolnum>8</manvolnum></citerefentry>, ++ <citerefentry project='man-pages'><refentrytitle>fsck.cramfs</refentrytitle><manvolnum>8</manvolnum></citerefentry>, ++ <citerefentry project='man-pages'><refentrytitle>fsck.ext4</refentrytitle><manvolnum>8</manvolnum></citerefentry>, ++ <citerefentry project='man-pages'><refentrytitle>fsck.fat</refentrytitle><manvolnum>8</manvolnum></citerefentry>, ++ <citerefentry project='man-pages'><refentrytitle>fsck.hfsplus</refentrytitle><manvolnum>8</manvolnum></citerefentry>, ++ <citerefentry project='man-pages'><refentrytitle>fsck.minix</refentrytitle><manvolnum>8</manvolnum></citerefentry>, ++ <citerefentry project='man-pages'><refentrytitle>fsck.ntfs</refentrytitle><manvolnum>8</manvolnum></citerefentry>, ++ <citerefentry project='man-pages'><refentrytitle>fsck.xfs</refentrytitle><manvolnum>8</manvolnum></citerefentry> ++ </para> ++ </refsect1> ++ ++</refentry> +diff --git a/meson.build b/meson.build +index 3afe168..b340139 100644 +--- a/meson.build ++++ b/meson.build +@@ -2396,6 +2396,14 @@ executable('systemd-makefs', + install : true, + install_dir : rootlibexecdir) + ++executable('systemd-fsckd', ++ 'src/fsckd/fsckd.c', ++ include_directories : includes, ++ link_with : [libshared], ++ install_rpath : rootlibexecdir, ++ install : true, ++ install_dir : rootlibexecdir) ++ + executable('systemd-sleep', + 'src/sleep/sleep.c', + include_directories : includes, +diff --git a/po/POTFILES.in b/po/POTFILES.in +index 029261c..d709ddb 100644 +--- a/po/POTFILES.in ++++ b/po/POTFILES.in +@@ -8,3 +8,4 @@ src/portable/org.freedesktop.portable1.policy + src/resolve/org.freedesktop.resolve1.policy + src/timedate/org.freedesktop.timedate1.policy + src/core/dbus-unit.c ++src/fsckd/fsckd.c +diff --git a/src/fsckd/fsckd.c b/src/fsckd/fsckd.c +new file mode 100644 +index 0000000..fffea29 +--- /dev/null ++++ b/src/fsckd/fsckd.c +@@ -0,0 +1,690 @@ ++/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ ++ ++/*** ++ This file is part of systemd. ++ ++ Copyright 2015 Canonical ++ ++ Author: ++ Didier Roche <didrocks@ubuntu.com> ++ ++ systemd is free software; you can redistribute it and/or modify it ++ under the terms of the GNU Lesser General Public License as published by ++ the Free Software Foundation; either version 2.1 of the License, or ++ (at your option) any later version. ++ ++ systemd is distributed in the hope that it will be useful, but ++ WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public License ++ along with systemd; If not, see <http://www.gnu.org/licenses/>. ++***/ ++ ++#include <getopt.h> ++#include <errno.h> ++#include <libintl.h> ++#include <math.h> ++#include <stdbool.h> ++#include <stdlib.h> ++#include <stdio.h> ++#include <sys/socket.h> ++#include <sys/types.h> ++#include <sys/un.h> ++#include <unistd.h> ++ ++#include "sd-daemon.h" ++#include "build.h" ++#include "def.h" ++#include "sd-event.h" ++#include "log.h" ++#include "list.h" ++#include "macro.h" ++#include "socket-util.h" ++#include "fd-util.h" ++#include "string-util.h" ++#include "io-util.h" ++#include "util.h" ++#include "alloc-util.h" ++#include "locale-util.h" ++ ++#define FSCKD_SOCKET_PATH "/run/systemd/fsck.progress" ++#define IDLE_TIME_SECONDS 30 ++#define PLYMOUTH_REQUEST_KEY "K\2\2\3" ++#define CLIENTS_MAX 128 ++ ++struct Manager; ++ ++typedef struct Client { ++ struct Manager *manager; ++ char *device_name; ++ /* device id refers to "fd <fd>" until it gets a name as "device_name" */ ++ char *device_id; ++ ++ pid_t fsck_pid; ++ FILE *fsck_f; ++ ++ size_t cur; ++ size_t max; ++ int pass; ++ ++ double percent; ++ ++ bool cancelled; ++ bool bad_input; ++ ++ sd_event_source *event_source; ++ ++ LIST_FIELDS(struct Client, clients); ++} Client; ++ ++typedef struct Manager { ++ sd_event *event; ++ ++ LIST_HEAD(Client, clients); ++ unsigned n_clients; ++ ++ size_t clear; ++ ++ int connection_fd; ++ sd_event_source *connection_event_source; ++ ++ bool show_status_console; ++ ++ double percent; ++ int numdevices; ++ ++ int plymouth_fd; ++ sd_event_source *plymouth_event_source; ++ bool plymouth_cancel_sent; ++ ++ bool cancel_requested; ++} Manager; ++ ++static void client_free(Client *c); ++static void manager_free(Manager *m); ++ ++DEFINE_TRIVIAL_CLEANUP_FUNC(Client*, client_free); ++DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free); ++ ++static int manager_write_console(Manager *m, const char *message) { ++ _cleanup_fclose_ FILE *console = NULL; ++ int l; ++ size_t j; ++ ++ assert(m); ++ ++ if (!m->show_status_console) ++ return 0; ++ ++ /* Reduce the SAK window by opening and closing console on every request */ ++ console = fopen("/dev/console", "we"); ++ if (!console) ++ return -errno; ++ ++ if (message) { ++ fprintf(console, "\r%s\r%n", message, &l); ++ if (m->clear < (size_t)l) ++ m->clear = (size_t)l; ++ } else { ++ fputc('\r', console); ++ for (j = 0; j < m->clear; j++) ++ fputc(' ', console); ++ fputc('\r', console); ++ } ++ fflush(console); ++ ++ return 0; ++} ++ ++static double compute_percent(int pass, size_t cur, size_t max) { ++ /* Values stolen from e2fsck */ ++ ++ static const double pass_table[] = { ++ 0, 70, 90, 92, 95, 100 ++ }; ++ ++ if (pass <= 0) ++ return 0.0; ++ ++ if ((unsigned) pass >= ELEMENTSOF(pass_table) || max == 0) ++ return 100.0; ++ ++ return pass_table[pass-1] + ++ (pass_table[pass] - pass_table[pass-1]) * ++ (double) cur / max; ++} ++ ++static int client_request_cancel(Client *c) { ++ assert(c); ++ ++ if (c->cancelled) ++ return 0; ++ ++ log_info("Request to cancel fsck for %s from fsckd", c->device_id); ++ if (kill(c->fsck_pid, SIGTERM) < 0) { ++ /* ignore the error and consider that cancel was sent if fsck just exited */ ++ if (errno != ESRCH) ++ return log_error_errno(errno, "Cannot send cancel to fsck for %s: %m", c->device_id); ++ } ++ ++ c->cancelled = true; ++ return 1; ++} ++ ++static void client_free(Client *c) { ++ assert(c); ++ ++ if (c->manager) { ++ LIST_REMOVE(clients, c->manager->clients, c); ++ c->manager->n_clients--; ++ } ++ ++ sd_event_source_unref(c->event_source); ++ fclose(c->fsck_f); ++ if (c->device_name) ++ free(c->device_name); ++ if (c->device_id) ++ free(c->device_id); ++ free(c); ++} ++ ++static void manager_disconnect_plymouth(Manager *m) { ++ assert(m); ++ ++ m->plymouth_event_source = sd_event_source_unref(m->plymouth_event_source); ++ m->plymouth_fd = safe_close(m->plymouth_fd); ++ m->plymouth_cancel_sent = false; ++} ++ ++static int manager_plymouth_feedback_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) { ++ Manager *m = userdata; ++ Client *current; ++ char buffer[6]; ++ ssize_t l; ++ ++ assert(m); ++ ++ l = read(m->plymouth_fd, buffer, sizeof(buffer)); ++ if (l < 0) { ++ log_warning_errno(errno, "Got error while reading from plymouth: %m"); ++ manager_disconnect_plymouth(m); ++ return -errno; ++ } ++ if (l == 0) { ++ manager_disconnect_plymouth(m); ++ return 0; ++ } ++ ++ if (l > 1 && buffer[0] == '\15') ++ log_error("Message update to plymouth wasn't delivered successfully"); ++ ++ /* the only answer support type we requested is a key interruption */ ++ if (l > 2 && buffer[0] == '\2' && buffer[5] == '\3') { ++ m->cancel_requested = true; ++ ++ /* cancel all connected clients */ ++ LIST_FOREACH(clients, current, m->clients) ++ client_request_cancel(current); ++ } ++ ++ return 0; ++} ++ ++static int manager_connect_plymouth(Manager *m) { ++ union sockaddr_union sa = PLYMOUTH_SOCKET; ++ int r; ++ ++ if (!plymouth_running()) ++ return 0; ++ ++ /* try to connect or reconnect if sending a message */ ++ if (m->plymouth_fd >= 0) ++ return 1; ++ ++ m->plymouth_fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0); ++ if (m->plymouth_fd < 0) ++ return log_warning_errno(errno, "Connection to plymouth socket failed: %m"); ++ ++ if (connect(m->plymouth_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1)) < 0) { ++ r = log_warning_errno(errno, "Couldn't connect to plymouth: %m"); ++ goto fail; ++ } ++ ++ r = sd_event_add_io(m->event, &m->plymouth_event_source, m->plymouth_fd, EPOLLIN, manager_plymouth_feedback_handler, m); ++ if (r < 0) { ++ log_warning_errno(r, "Can't listen to plymouth socket: %m"); ++ goto fail; ++ } ++ ++ return 1; ++ ++fail: ++ manager_disconnect_plymouth(m); ++ return r; ++} ++ ++static int plymouth_send_message(int plymouth_fd, const char *message, bool update) { ++ _cleanup_free_ char *packet = NULL; ++ int n; ++ char mode = 'M'; ++ ++ if (update) ++ mode = 'U'; ++ ++ if (asprintf(&packet, "%c\002%c%s%n", mode, (int) (strlen(message) + 1), message, &n) < 0) ++ return log_oom(); ++ ++ return loop_write(plymouth_fd, packet, n + 1, true); ++} ++ ++static int manager_send_plymouth_message(Manager *m, const char *message) { ++ const char *plymouth_cancel_message = NULL, *l10n_cancel_message = NULL; ++ int r; ++ ++ r = manager_connect_plymouth(m); ++ if (r < 0) ++ return r; ++ /* 0 means that plymouth isn't running, do not send any message yet */ ++ else if (r == 0) ++ return 0; ++ ++ if (!m->plymouth_cancel_sent) { ++ ++ /* Indicate to plymouth that we listen to Ctrl+C */ ++ r = loop_write(m->plymouth_fd, PLYMOUTH_REQUEST_KEY, sizeof(PLYMOUTH_REQUEST_KEY), true); ++ if (r < 0) ++ return log_warning_errno(r, "Can't send to plymouth cancel key: %m"); ++ ++ m->plymouth_cancel_sent = true; ++ ++ l10n_cancel_message = _("Press Ctrl+C to cancel all filesystem checks in progress"); ++ plymouth_cancel_message = strjoina("fsckd-cancel-msg:", l10n_cancel_message); ++ ++ r = plymouth_send_message(m->plymouth_fd, plymouth_cancel_message, false); ++ if (r < 0) ++ log_warning_errno(r, "Can't send filesystem cancel message to plymouth: %m"); ++ ++ } else if (m->numdevices == 0) { ++ ++ m->plymouth_cancel_sent = false; ++ ++ r = plymouth_send_message(m->plymouth_fd, "", false); ++ if (r < 0) ++ log_warning_errno(r, "Can't clear plymouth filesystem cancel message: %m"); ++ } ++ ++ r = plymouth_send_message(m->plymouth_fd, message, true); ++ if (r < 0) ++ return log_warning_errno(r, "Couldn't send \"%s\" to plymouth: %m", message); ++ ++ return 0; ++} ++ ++static int manager_update_global_progress(Manager *m) { ++ Client *current = NULL; ++ _cleanup_free_ char *console_message = NULL; ++ _cleanup_free_ char *fsck_message = NULL; ++ int current_numdevices = 0, r; ++ double current_percent = 100; ++ ++ /* get the overall percentage */ ++ LIST_FOREACH(clients, current, m->clients) { ++ current_numdevices++; ++ ++ /* right now, we only keep the minimum % of all fsckd processes. We could in the future trying to be ++ linear, but max changes and corresponds to the pass. We have all the informations into fsckd ++ already if we can treat that in a smarter way. */ ++ current_percent = MIN(current_percent, current->percent); ++ } ++ ++ /* update if there is anything user-visible to update */ ++ if (fabs(current_percent - m->percent) > 0.001 || current_numdevices != m->numdevices) { ++ m->numdevices = current_numdevices; ++ m->percent = current_percent; ++ ++ if (asprintf(&console_message, ++ ngettext("Checking in progress on %d disk (%3.1f%% complete)", ++ "Checking in progress on %d disks (%3.1f%% complete)", m->numdevices), ++ m->numdevices, m->percent) < 0) ++ return -ENOMEM; ++ ++ if (asprintf(&fsck_message, "fsckd:%d:%3.1f:%s", m->numdevices, m->percent, console_message) < 0) ++ return -ENOMEM; ++ ++ r = manager_write_console(m, console_message); ++ if (r < 0) ++ return r; ++ ++ /* try to connect to plymouth and send message */ ++ r = manager_send_plymouth_message(m, fsck_message); ++ if (r < 0) ++ return r; ++ } ++ return 0; ++} ++ ++static int client_progress_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) { ++ Client *client = userdata; ++ char line[LINE_MAX]; ++ Manager *m; ++ ++ assert(client); ++ m = client->manager; ++ ++ /* check first if we need to cancel this client */ ++ if (m->cancel_requested) ++ client_request_cancel(client); ++ ++ while (fgets(line, sizeof(line), client->fsck_f) != NULL) { ++ int pass; ++ size_t cur, max; ++ _cleanup_free_ char *device = NULL, *old_device_id = NULL; ++ ++ if (sscanf(line, "%i %zu %zu %ms", &pass, &cur, &max, &device) == 4) { ++ if (!client->device_name) { ++ client->device_name = strdup(device); ++ if (!client->device_name) { ++ log_oom(); ++ continue; ++ } ++ old_device_id = client->device_id; ++ client->device_id = strdup(device); ++ if (!client->device_id) { ++ log_oom(); ++ client->device_id = old_device_id; ++ old_device_id = NULL; ++ continue; ++ } ++ } ++ client->pass = pass; ++ client->cur = cur; ++ client->max = max; ++ client->bad_input = false; ++ client->percent = compute_percent(client->pass, client->cur, client->max); ++ log_debug("Getting progress for %s (%zu, %zu, %d) : %3.1f%%", client->device_id, ++ client->cur, client->max, client->pass, client->percent); ++ } else { ++ if (errno == ENOMEM) { ++ log_oom(); ++ continue; ++ } ++ ++ /* if previous input was already garbage, kick it off from progress report */ ++ if (client->bad_input) { ++ log_warning("Closing connection on incorrect input of fsck connection for %s", client->device_id); ++ client_free(client); ++ manager_update_global_progress(m); ++ return 0; ++ } ++ client->bad_input = true; ++ } ++ ++ } ++ ++ if (feof(client->fsck_f)) { ++ log_debug("Fsck client %s disconnected", client->device_id); ++ client_free(client); ++ } ++ ++ manager_update_global_progress(m); ++ return 0; ++} ++ ++static int manager_new_connection_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) { ++ _cleanup_(client_freep) Client *c = NULL; ++ _cleanup_close_ int new_fsck_fd = -1; ++ _cleanup_fclose_ FILE *new_fsck_f = NULL; ++ struct ucred ucred = {}; ++ Manager *m = userdata; ++ int r; ++ ++ assert(m); ++ ++ /* Initialize and list new clients */ ++ new_fsck_fd = accept4(m->connection_fd, NULL, NULL, SOCK_CLOEXEC|SOCK_NONBLOCK); ++ if (new_fsck_fd < 0) { ++ log_error_errno(errno, "Couldn't accept a new connection: %m"); ++ return 0; ++ } ++ ++ if (m->n_clients >= CLIENTS_MAX) { ++ log_error("Too many clients, refusing connection."); ++ return 0; ++ } ++ ++ ++ new_fsck_f = fdopen(new_fsck_fd, "r"); ++ if (!new_fsck_f) { ++ log_error_errno(errno, "Couldn't fdopen new connection for fd %d: %m", new_fsck_fd); ++ return 0; ++ } ++ new_fsck_fd = -1; ++ ++ r = getpeercred(fileno(new_fsck_f), &ucred); ++ if (r < 0) { ++ log_error_errno(r, "Couldn't get credentials for fsck: %m"); ++ return 0; ++ } ++ ++ c = new0(Client, 1); ++ if (!c) { ++ log_oom(); ++ return 0; ++ } ++ ++ c->fsck_pid = ucred.pid; ++ c->fsck_f = new_fsck_f; ++ new_fsck_f = NULL; ++ ++ if (asprintf(&(c->device_id), "fd %d", fileno(c->fsck_f)) < 0) { ++ log_oom(); ++ return 0; ++ } ++ ++ r = sd_event_add_io(m->event, &c->event_source, fileno(c->fsck_f), EPOLLIN, client_progress_handler, c); ++ if (r < 0) { ++ log_oom(); ++ return 0; ++ } ++ ++ LIST_PREPEND(clients, m->clients, c); ++ m->n_clients++; ++ c->manager = m; ++ ++ log_debug("New fsck client connected: %s", c->device_id); ++ ++ /* only request the client to cancel now in case the request is dropped by the client (chance to recancel) */ ++ if (m->cancel_requested) ++ client_request_cancel(c); ++ ++ c = NULL; ++ return 0; ++} ++ ++static void manager_free(Manager *m) { ++ if (!m) ++ return; ++ ++ /* clear last line */ ++ manager_write_console(m, NULL); ++ ++ sd_event_source_unref(m->connection_event_source); ++ safe_close(m->connection_fd); ++ ++ while (m->clients) ++ client_free(m->clients); ++ ++ manager_disconnect_plymouth(m); ++ ++ sd_event_unref(m->event); ++ ++ free(m); ++} ++ ++static int manager_new(Manager **ret, int fd) { ++ _cleanup_(manager_freep) Manager *m = NULL; ++ int r; ++ ++ assert(ret); ++ ++ m = new0(Manager, 1); ++ if (!m) ++ return -ENOMEM; ++ ++ m->plymouth_fd = -1; ++ m->connection_fd = fd; ++ m->percent = 100; ++ ++ r = sd_event_default(&m->event); ++ if (r < 0) ++ return r; ++ ++ if (access("/run/systemd/show-status", F_OK) >= 0) ++ m->show_status_console = true; ++ ++ r = sd_event_add_io(m->event, &m->connection_event_source, fd, EPOLLIN, manager_new_connection_handler, m); ++ if (r < 0) ++ return r; ++ ++ *ret = m; ++ m = NULL; ++ ++ return 0; ++} ++ ++static int run_event_loop_with_timeout(Manager *m, usec_t timeout) { ++ int r, code; ++ sd_event *e = m->event; ++ ++ assert(e); ++ ++ for (;;) { ++ r = sd_event_get_state(e); ++ if (r < 0) ++ return r; ++ if (r == SD_EVENT_FINISHED) ++ break; ++ ++ r = sd_event_run(e, timeout); ++ if (r < 0) ++ return r; ++ ++ /* Exit if we reached the idle timeout and no more clients are ++ connected. If there is still an fsck process running but ++ simply slow to send us progress updates, exiting would mean ++ that this fsck process receives SIGPIPE resulting in an ++ aborted file system check. */ ++ if (r == 0 && m->n_clients == 0) { ++ sd_event_exit(e, 0); ++ break; ++ } ++ } ++ ++ r = sd_event_get_exit_code(e, &code); ++ if (r < 0) ++ return r; ++ ++ return code; ++} ++ ++static void help(void) { ++ printf("%s [OPTIONS...]\n\n" ++ "Capture fsck progress and forward one stream to plymouth\n\n" ++ " -h --help Show this help\n" ++ " --version Show package version\n", ++ program_invocation_short_name); ++} ++ ++static int parse_argv(int argc, char *argv[]) { ++ ++ enum { ++ ARG_VERSION = 0x100, ++ ARG_ROOT, ++ }; ++ ++ static const struct option options[] = { ++ { "help", no_argument, NULL, 'h' }, ++ { "version", no_argument, NULL, ARG_VERSION }, ++ {} ++ }; ++ ++ int c; ++ ++ assert(argc >= 0); ++ assert(argv); ++ ++ while ((c = getopt_long(argc, argv, "hv", options, NULL)) >= 0) ++ switch (c) { ++ ++ case 'h': ++ help(); ++ return 0; ++ ++ case ARG_VERSION: ++ puts("systemd " GIT_VERSION); ++ puts(SYSTEMD_FEATURES); ++ return 0; ++ ++ case '?': ++ return -EINVAL; ++ ++ default: ++ assert_not_reached("Unhandled option"); ++ } ++ ++ if (optind < argc) { ++ log_error("Extraneous arguments"); ++ return -EINVAL; ++ } ++ ++ return 1; ++} ++ ++int main(int argc, char *argv[]) { ++ _cleanup_(manager_freep) Manager *m = NULL; ++ int fd = -1; ++ int r, n; ++ ++ log_set_target(LOG_TARGET_AUTO); ++ log_parse_environment(); ++ log_open(); ++ init_gettext(); ++ ++ r = parse_argv(argc, argv); ++ if (r <= 0) ++ goto finish; ++ ++ n = sd_listen_fds(0); ++ if (n > 1) { ++ log_error("Too many file descriptors received."); ++ r = -EINVAL; ++ goto finish; ++ } else if (n == 1) ++ fd = SD_LISTEN_FDS_START + 0; ++ else { ++ fd = make_socket_fd(LOG_DEBUG, FSCKD_SOCKET_PATH, SOCK_STREAM, SOCK_CLOEXEC); ++ if (fd < 0) { ++ r = log_error_errno(fd, "Couldn't create listening socket fd on %s: %m", FSCKD_SOCKET_PATH); ++ goto finish; ++ } ++ } ++ ++ r = manager_new(&m, fd); ++ if (r < 0) { ++ log_error_errno(r, "Failed to allocate manager: %m"); ++ goto finish; ++ } ++ ++ r = run_event_loop_with_timeout(m, IDLE_TIME_SECONDS * USEC_PER_SEC); ++ if (r < 0) { ++ log_error_errno(r, "Failed to run event loop: %m"); ++ goto finish; ++ } ++ ++ sd_event_get_exit_code(m->event, &r); ++ ++finish: ++ return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; ++} +diff --git a/units/meson.build b/units/meson.build +index d695084..ab489b3 100644 +--- a/units/meson.build ++++ b/units/meson.build +@@ -87,6 +87,7 @@ units = [ + ['systemd-coredump.socket', 'ENABLE_COREDUMP', + 'sockets.target.wants/'], + ['systemd-exit.service', ''], ++ ['systemd-fsckd.socket', ''], + ['systemd-initctl.socket', '', + 'sockets.target.wants/'], + ['systemd-journal-gatewayd.socket', 'ENABLE_REMOTE HAVE_MICROHTTPD'], +@@ -143,6 +144,7 @@ in_units = [ + 'sysinit.target.wants/'], + ['systemd-fsck-root.service', ''], + ['systemd-fsck@.service', ''], ++ ['systemd-fsckd.service', ''], + ['systemd-halt.service', ''], + ['systemd-hibernate-resume@.service', 'ENABLE_HIBERNATE'], + ['systemd-hibernate.service', 'ENABLE_HIBERNATE'], +diff --git a/units/systemd-fsck-root.service.in b/units/systemd-fsck-root.service.in +index 042081c..bea6c16 100644 +--- a/units/systemd-fsck-root.service.in ++++ b/units/systemd-fsck-root.service.in +@@ -13,6 +13,8 @@ Documentation=man:systemd-fsck-root.service(8) + DefaultDependencies=no + Conflicts=shutdown.target + Before=local-fs.target shutdown.target ++Wants=systemd-fsckd.socket ++After=systemd-fsckd.socket + ConditionPathIsReadWrite=!/ + + [Service] +diff --git a/units/systemd-fsck@.service.in b/units/systemd-fsck@.service.in +index 3322083..bfa565b 100644 +--- a/units/systemd-fsck@.service.in ++++ b/units/systemd-fsck@.service.in +@@ -13,7 +13,8 @@ Documentation=man:systemd-fsck@.service(8) + DefaultDependencies=no + BindsTo=%i.device + Conflicts=shutdown.target +-After=%i.device systemd-fsck-root.service local-fs-pre.target ++Wants=systemd-fsckd.socket ++After=%i.device systemd-fsck-root.service local-fs-pre.target systemd-fsckd.socket + Before=systemd-quotacheck.service shutdown.target + + [Service] +diff --git a/units/systemd-fsckd.service.in b/units/systemd-fsckd.service.in +new file mode 100644 +index 0000000..9c7ed51 +--- /dev/null ++++ b/units/systemd-fsckd.service.in +@@ -0,0 +1,17 @@ ++# This file is part of systemd. ++# ++# systemd is free software; you can redistribute it and/or modify it ++# under the terms of the GNU Lesser General Public License as published by ++# the Free Software Foundation; either version 2.1 of the License, or ++# (at your option) any later version. ++ ++[Unit] ++Description=File System Check Daemon to report status ++Documentation=man:systemd-fsckd.service(8) ++DefaultDependencies=no ++Requires=systemd-fsckd.socket ++Before=shutdown.target ++ ++[Service] ++ExecStart=@rootlibexecdir@/systemd-fsckd ++StandardOutput=journal+console +diff --git a/units/systemd-fsckd.socket b/units/systemd-fsckd.socket +new file mode 100644 +index 0000000..61fec97 +--- /dev/null ++++ b/units/systemd-fsckd.socket +@@ -0,0 +1,15 @@ ++# This file is part of systemd. ++# ++# systemd is free software; you can redistribute it and/or modify it ++# under the terms of the GNU Lesser General Public License as published by ++# the Free Software Foundation; either version 2.1 of the License, or ++# (at your option) any later version. ++ ++[Unit] ++Description=fsck to fsckd communication Socket ++Documentation=man:systemd-fsckd.service(8) man:systemd-fsck@.service(8) man:systemd-fsck-root.service(8) ++DefaultDependencies=no ++ ++[Socket] ++ListenStream=/run/systemd/fsck.progress ++SocketMode=0600 diff --git a/debian/patches/execute-remove-one-redundant-comparison-check.patch b/debian/patches/execute-remove-one-redundant-comparison-check.patch new file mode 100644 index 0000000..d29ece3 --- /dev/null +++ b/debian/patches/execute-remove-one-redundant-comparison-check.patch @@ -0,0 +1,29 @@ +From: Lennart Poettering <lennart@poettering.net> +Date: Thu, 14 Mar 2019 17:01:46 +0100 +Subject: execute: remove one redundant comparison check + +(cherry picked from commit d484580ca6f0e79abe6f3f5c677323a22d9e22d7) +--- + 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 f2a4c54..5486e37 100644 +--- a/src/core/execute.c ++++ b/src/core/execute.c +@@ -2158,11 +2158,12 @@ static int setup_exec_directory( + } + } else { + r = mkdir_label(p, context->directories[type].mode); +- if (r < 0 && r != -EEXIST) +- goto fail; +- if (r == -EEXIST) { ++ if (r < 0) { + struct stat st; + ++ if (r != -EEXIST) ++ goto fail; ++ + if (stat(p, &st) < 0) { + r = -errno; + goto fail; diff --git a/debian/patches/journal-do-not-trigger-assertion-when-journal_file_close-.patch b/debian/patches/journal-do-not-trigger-assertion-when-journal_file_close-.patch new file mode 100644 index 0000000..9cb536b --- /dev/null +++ b/debian/patches/journal-do-not-trigger-assertion-when-journal_file_close-.patch @@ -0,0 +1,46 @@ +From: Yu Watanabe <watanabe.yu+github@gmail.com> +Date: Tue, 28 May 2019 12:40:17 +0900 +Subject: journal: do not trigger assertion when journal_file_close() get NULL + +We generally expect destructors to not complain if a NULL argument is passed. + +Closes #12400. + +(cherry picked from commit c377a6f3ad3d9bed4ce7e873e8e9ec6b1650c57d) +--- + src/journal/journal-file.c | 3 ++- + src/journal/journald-server.c | 7 ++----- + 2 files changed, 4 insertions(+), 6 deletions(-) + +diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c +index 56827f9..04cf1ef 100644 +--- a/src/journal/journal-file.c ++++ b/src/journal/journal-file.c +@@ -335,7 +335,8 @@ bool journal_file_is_offlining(JournalFile *f) { + } + + JournalFile* journal_file_close(JournalFile *f) { +- assert(f); ++ if (!f) ++ return NULL; + + #if HAVE_GCRYPT + /* Write the final tag */ +diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c +index 2a960eb..ba0b35d 100644 +--- a/src/journal/journald-server.c ++++ b/src/journal/journald-server.c +@@ -2037,11 +2037,8 @@ void server_done(Server *s) { + + client_context_flush_all(s); + +- if (s->system_journal) +- (void) journal_file_close(s->system_journal); +- +- if (s->runtime_journal) +- (void) journal_file_close(s->runtime_journal); ++ (void) journal_file_close(s->system_journal); ++ (void) journal_file_close(s->runtime_journal); + + ordered_hashmap_free_with_destructor(s->user_journals, journal_file_close); + diff --git a/debian/patches/journal-remote-do-not-request-Content-Length-if-Transfer-.patch b/debian/patches/journal-remote-do-not-request-Content-Length-if-Transfer-.patch new file mode 100644 index 0000000..a8ab578 --- /dev/null +++ b/debian/patches/journal-remote-do-not-request-Content-Length-if-Transfer-.patch @@ -0,0 +1,74 @@ +From: Yu Watanabe <watanabe.yu+github@gmail.com> +Date: Mon, 11 Mar 2019 12:27:18 +0900 +Subject: 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) +--- + 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 802c3ea..2321a91 100644 +--- a/src/journal-remote/journal-remote-main.c ++++ b/src/journal-remote/journal-remote-main.c +@@ -265,6 +265,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); +@@ -290,21 +291,33 @@ static int request_handler( + return mhd_respond(connection, MHD_HTTP_UNSUPPORTED_MEDIA_TYPE, + "Content-Type: application/vnd.fdo.journal is required."); + ++ header = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, "Transfer-Encoding"); ++ if (header) { ++ if (!strcaseeq(header, "chunked")) ++ return mhd_respondf(connection, 0, MHD_HTTP_BAD_REQUEST, ++ "Unsupported Transfer-Encoding type: %s", header); ++ ++ chunked = true; ++ } ++ + header = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, "Content-Length"); +- if (!header) +- return mhd_respond(connection, MHD_HTTP_LENGTH_REQUIRED, +- "Content-Length header is required."); +- r = safe_atozu(header, &len); +- if (r < 0) +- return mhd_respondf(connection, r, MHD_HTTP_LENGTH_REQUIRED, +- "Content-Length: %s cannot be parsed: %m", header); +- +- if (len > ENTRY_SIZE_MAX) +- /* When serialized, an entry of maximum size might be slightly larger, +- * so this does not correspond exactly to the limit in journald. Oh well. +- */ +- return mhd_respondf(connection, 0, MHD_HTTP_PAYLOAD_TOO_LARGE, +- "Payload larger than maximum size of %u bytes", ENTRY_SIZE_MAX); ++ if (header) { ++ if (chunked) ++ return mhd_respond(connection, MHD_HTTP_BAD_REQUEST, ++ "Content-Length must not specified when Transfer-Encoding type is 'chuncked'"); ++ ++ r = safe_atozu(header, &len); ++ if (r < 0) ++ return mhd_respondf(connection, r, MHD_HTTP_LENGTH_REQUIRED, ++ "Content-Length: %s cannot be parsed: %m", header); ++ ++ if (len > ENTRY_SIZE_MAX) ++ /* When serialized, an entry of maximum size might be slightly larger, ++ * so this does not correspond exactly to the limit in journald. Oh well. ++ */ ++ return mhd_respondf(connection, 0, MHD_HTTP_PAYLOAD_TOO_LARGE, ++ "Payload larger than maximum size of %u bytes", ENTRY_SIZE_MAX); ++ } + + { + const union MHD_ConnectionInfo *ci; diff --git a/debian/patches/login-add-a-missing-error-check-for-session_set_leader.patch b/debian/patches/login-add-a-missing-error-check-for-session_set_leader.patch new file mode 100644 index 0000000..ba8bfa9 --- /dev/null +++ b/debian/patches/login-add-a-missing-error-check-for-session_set_leader.patch @@ -0,0 +1,29 @@ +From: Yu Watanabe <watanabe.yu+github@gmail.com> +Date: Thu, 14 Feb 2019 10:59:13 +0900 +Subject: login: add a missing error check for session_set_leader() + +session_set_leader() may fail. If it fails, then manager_start_scope() +will trigger assertion. + +This may be related to RHBZ#1663704. + +(cherry picked from commit fe3ab8458b9c0ead4b3e14ac25b342d8c34376fe) +--- + src/login/logind-dbus.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c +index 8ab498f..b9ea370 100644 +--- a/src/login/logind-dbus.c ++++ b/src/login/logind-dbus.c +@@ -790,7 +790,9 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus + goto fail; + + session_set_user(session, user); +- session_set_leader(session, leader); ++ r = session_set_leader(session, leader); ++ if (r < 0) ++ goto fail; + + session->type = t; + session->class = c; diff --git a/debian/patches/man-add-note-that-h-u-U-are-mostly-useless.patch b/debian/patches/man-add-note-that-h-u-U-are-mostly-useless.patch new file mode 100644 index 0000000..31a95da --- /dev/null +++ b/debian/patches/man-add-note-that-h-u-U-are-mostly-useless.patch @@ -0,0 +1,45 @@ +From: =?utf-8?q?Zbigniew_J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl> +Date: Tue, 21 May 2019 19:31:49 +0200 +Subject: man: add note that %h/%u/%U are mostly useless + +Fixes #12389. + +(cherry picked from commit b4e2407716731d1ce099bad1c2778f7a4424ed2e) +--- + man/systemd.unit.xml | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml +index f21f9ea..be6355d 100644 +--- a/man/systemd.unit.xml ++++ b/man/systemd.unit.xml +@@ -1580,7 +1580,9 @@ + <row> + <entry><literal>%h</literal></entry> + <entry>User home directory</entry> +- <entry>This is the home directory of the user running the service manager instance. In case of the system manager this resolves to <literal>/root</literal>.</entry> ++ <entry>This is the home directory of the <emphasis>user running the service manager instance</emphasis>. In case of the system manager this resolves to <literal>/root</literal>. ++ ++Note that this setting is <emphasis>not</emphasis> influenced by the <varname>User=</varname> setting configurable in the [Service] section of the service unit.</entry> + </row> + <row> + <entry><literal>%H</literal></entry> +@@ -1670,12 +1672,16 @@ + <row> + <entry><literal>%u</literal></entry> + <entry>User name</entry> +- <entry>This is the name of the user running the service manager instance. In case of the system manager this resolves to <literal>root</literal>.</entry> ++ <entry>This is the name of the <emphasis>user running the service manager instance</emphasis>. In case of the system manager this resolves to <literal>root</literal>. ++ ++Note that this setting is <emphasis>not</emphasis> influenced by the <varname>User=</varname> setting configurable in the [Service] section of the service unit.</entry> + </row> + <row> + <entry><literal>%U</literal></entry> + <entry>User UID</entry> +- <entry>This is the numeric UID of the user running the service manager instance. In case of the system manager this resolves to <literal>0</literal>.</entry> ++ <entry>This is the numeric UID of the <emphasis>user running the service manager instance</emphasis>. In case of the system manager this resolves to <literal>0</literal>. ++ ++Note that this setting is <emphasis>not</emphasis> influenced by the <varname>User=</varname> setting configurable in the [Service] section of the service unit.</entry> + </row> + <row> + <entry><literal>%v</literal></entry> diff --git a/debian/patches/meson-make-nologin-path-build-time-configurable.patch b/debian/patches/meson-make-nologin-path-build-time-configurable.patch new file mode 100644 index 0000000..38c91d7 --- /dev/null +++ b/debian/patches/meson-make-nologin-path-build-time-configurable.patch @@ -0,0 +1,354 @@ +From: Michael Biebl <biebl@debian.org> +Date: Thu, 18 Jul 2019 01:24:00 +0200 +Subject: meson: make nologin path build time configurable + +Some distros install nologin as /usr/sbin/nologin, others as +/sbin/nologin. +Since we can't really on merged-usr everywhere (where the path wouldn't +matter), make the path build time configurable via -Dnologin-path=. + +Closes #13028 + +(cherry picked from commit 6db904625d413739c480ddbe7667d3f40acc4ae0) +--- + man/nss-mymachines.xml | 4 ++-- + man/sysusers.d.xml | 4 ++-- + meson.build | 1 + + meson_options.txt | 1 + + src/basic/user-util.c | 4 ++-- + src/nss-mymachines/nss-mymachines.c | 4 ++-- + src/nss-systemd/nss-systemd.c | 4 ++-- + src/sysusers/sysusers.c | 2 +- + src/test/test-user-util.c | 4 ++-- + test/TEST-21-SYSUSERS/test-1.expected-passwd | 2 +- + test/TEST-21-SYSUSERS/test-10.expected-passwd | 4 ++-- + test/TEST-21-SYSUSERS/test-11.expected-passwd | 2 +- + test/TEST-21-SYSUSERS/test-12.expected-passwd | 2 +- + test/TEST-21-SYSUSERS/test-2.expected-passwd | 2 +- + test/TEST-21-SYSUSERS/test-3.expected-passwd | 8 +++---- + test/TEST-21-SYSUSERS/test-4.expected-passwd | 4 ++-- + test/TEST-21-SYSUSERS/test-5.expected-passwd | 34 +++++++++++++-------------- + test/TEST-21-SYSUSERS/test-6.expected-passwd | 2 +- + test/TEST-21-SYSUSERS/test-7.expected-passwd | 10 ++++---- + test/TEST-21-SYSUSERS/test-8.expected-passwd | 2 +- + test/TEST-21-SYSUSERS/test-9.expected-passwd | 4 ++-- + test/TEST-21-SYSUSERS/test.sh | 9 ++++++- + 22 files changed, 61 insertions(+), 52 deletions(-) + +diff --git a/man/nss-mymachines.xml b/man/nss-mymachines.xml +index 5742d89..5100cd0 100644 +--- a/man/nss-mymachines.xml ++++ b/man/nss-mymachines.xml +@@ -101,8 +101,8 @@ MACHINE CLASS SERVICE OS VERSION ADDRESSES + rawhide container systemd-nspawn fedora 30 169.254.40.164 fe80::94aa:3aff:fe7b:d4b9 + + $ getent passwd vu-rawhide-0 vu-rawhide-81 +-vu-rawhide-0:*:20119552:65534:vu-rawhide-0:/:/sbin/nologin +-vu-rawhide-81:*:20119633:65534:vu-rawhide-81:/:/sbin/nologin ++vu-rawhide-0:*:20119552:65534:vu-rawhide-0:/:/usr/sbin/nologin ++vu-rawhide-81:*:20119633:65534:vu-rawhide-81:/:/usr/sbin/nologin + + $ getent group vg-rawhide-0 vg-rawhide-81 + vg-rawhide-0:*:20119552: +diff --git a/man/sysusers.d.xml b/man/sysusers.d.xml +index e47d36c..b470532 100644 +--- a/man/sysusers.d.xml ++++ b/man/sysusers.d.xml +@@ -207,12 +207,12 @@ u root 0 "Superuser" /root /bin/zsh</pro + <title>Shell</title> + + <para>The login shell of the user. If not specified, this will be set to +- <filename>/sbin/nologin</filename>, except if the UID of the user is 0, in ++ <filename>/usr/sbin/nologin</filename>, except if the UID of the user is 0, in + which case <filename>/bin/sh</filename> will be used.</para> + + <para>Only applies to lines of type <varname>u</varname> and should otherwise + be left unset (or <literal>-</literal>). It is recommended to omit this, unless +- a shell different <filename>/sbin/nologin</filename> must be used.</para> ++ a shell different <filename>/usr/sbin/nologin</filename> must be used.</para> + </refsect2> + </refsect1> + +diff --git a/meson.build b/meson.build +index d340736..3afe168 100644 +--- a/meson.build ++++ b/meson.build +@@ -611,6 +611,7 @@ progs = [['quotaon', '/usr/sbin/quotaon' ], + ['umount', '/usr/bin/umount', 'UMOUNT_PATH'], + ['loadkeys', '/usr/bin/loadkeys', 'KBD_LOADKEYS'], + ['setfont', '/usr/bin/setfont', 'KBD_SETFONT'], ++ ['nologin', '/usr/sbin/nologin', ], + ] + foreach prog : progs + path = get_option(prog[0] + '-path') +diff --git a/meson_options.txt b/meson_options.txt +index 044bb79..6304511 100644 +--- a/meson_options.txt ++++ b/meson_options.txt +@@ -43,6 +43,7 @@ option('mount-path', type : 'string', description : 'path to mount') + option('umount-path', type : 'string', description : 'path to umount') + option('loadkeys-path', type : 'string', description : 'path to loadkeys') + option('setfont-path', type : 'string', description : 'path to setfont') ++option('nologin-path', type : 'string', description : 'path to nologin') + + option('debug-shell', type : 'string', value : '/bin/sh', + description : 'path to debug shell binary') +diff --git a/src/basic/user-util.c b/src/basic/user-util.c +index 260f3d2..78656d9 100644 +--- a/src/basic/user-util.c ++++ b/src/basic/user-util.c +@@ -146,7 +146,7 @@ static int synthesize_user_creds( + *home = FLAGS_SET(flags, USER_CREDS_CLEAN) ? NULL : "/"; + + if (shell) +- *shell = FLAGS_SET(flags, USER_CREDS_CLEAN) ? NULL : "/sbin/nologin"; ++ *shell = FLAGS_SET(flags, USER_CREDS_CLEAN) ? NULL : NOLOGIN; + + return 0; + } +@@ -522,7 +522,7 @@ int get_shell(char **_s) { + } + if (synthesize_nobody() && + u == UID_NOBODY) { +- s = strdup("/sbin/nologin"); ++ s = strdup(NOLOGIN); + if (!s) + return -ENOMEM; + +diff --git a/src/nss-mymachines/nss-mymachines.c b/src/nss-mymachines/nss-mymachines.c +index 486a658..d576e69 100644 +--- a/src/nss-mymachines/nss-mymachines.c ++++ b/src/nss-mymachines/nss-mymachines.c +@@ -501,7 +501,7 @@ enum nss_status _nss_mymachines_getpwnam_r( + pwd->pw_gecos = buffer; + pwd->pw_passwd = (char*) "*"; /* locked */ + pwd->pw_dir = (char*) "/"; +- pwd->pw_shell = (char*) "/sbin/nologin"; ++ pwd->pw_shell = (char*) NOLOGIN; + + return NSS_STATUS_SUCCESS; + +@@ -581,7 +581,7 @@ enum nss_status _nss_mymachines_getpwuid_r( + pwd->pw_gecos = buffer; + pwd->pw_passwd = (char*) "*"; /* locked */ + pwd->pw_dir = (char*) "/"; +- pwd->pw_shell = (char*) "/sbin/nologin"; ++ pwd->pw_shell = (char*) NOLOGIN; + + return NSS_STATUS_SUCCESS; + +diff --git a/src/nss-systemd/nss-systemd.c b/src/nss-systemd/nss-systemd.c +index f8db27a..0ca0e8d 100644 +--- a/src/nss-systemd/nss-systemd.c ++++ b/src/nss-systemd/nss-systemd.c +@@ -23,7 +23,7 @@ + #define DYNAMIC_USER_GECOS "Dynamic User" + #define DYNAMIC_USER_PASSWD "*" /* locked */ + #define DYNAMIC_USER_DIR "/" +-#define DYNAMIC_USER_SHELL "/sbin/nologin" ++#define DYNAMIC_USER_SHELL NOLOGIN + + static const struct passwd root_passwd = { + .pw_name = (char*) "root", +@@ -42,7 +42,7 @@ static const struct passwd nobody_passwd = { + .pw_gid = GID_NOBODY, + .pw_gecos = (char*) "User Nobody", + .pw_dir = (char*) "/", +- .pw_shell = (char*) "/sbin/nologin", ++ .pw_shell = (char*) NOLOGIN, + }; + + static const struct group root_group = { +diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c +index df28bcf..91d46a7 100644 +--- a/src/sysusers/sysusers.c ++++ b/src/sysusers/sysusers.c +@@ -361,7 +361,7 @@ static int rename_and_apply_smack(const char *temp_path, const char *dest_path) + } + + static const char* default_shell(uid_t uid) { +- return uid == 0 ? "/bin/sh" : "/sbin/nologin"; ++ return uid == 0 ? "/bin/sh" : NOLOGIN; + } + + static int write_temporary_passwd(const char *passwd_path, FILE **tmpfile, char **tmpfile_path) { +diff --git a/src/test/test-user-util.c b/src/test/test-user-util.c +index 801824a..2e303ad 100644 +--- a/src/test/test-user-util.c ++++ b/src/test/test-user-util.c +@@ -205,8 +205,8 @@ int main(int argc, char *argv[]) { + + test_get_user_creds_one("root", "root", 0, 0, "/root", "/bin/sh"); + test_get_user_creds_one("0", "root", 0, 0, "/root", "/bin/sh"); +- test_get_user_creds_one(NOBODY_USER_NAME, NOBODY_USER_NAME, UID_NOBODY, GID_NOBODY, "/", "/sbin/nologin"); +- test_get_user_creds_one("65534", NOBODY_USER_NAME, UID_NOBODY, GID_NOBODY, "/", "/sbin/nologin"); ++ test_get_user_creds_one(NOBODY_USER_NAME, NOBODY_USER_NAME, UID_NOBODY, GID_NOBODY, "/", NOLOGIN); ++ test_get_user_creds_one("65534", NOBODY_USER_NAME, UID_NOBODY, GID_NOBODY, "/", NOLOGIN); + + test_get_group_creds_one("root", "root", 0); + test_get_group_creds_one("0", "root", 0); +diff --git a/test/TEST-21-SYSUSERS/test-1.expected-passwd b/test/TEST-21-SYSUSERS/test-1.expected-passwd +index 8d0bfff..f59303b 100644 +--- a/test/TEST-21-SYSUSERS/test-1.expected-passwd ++++ b/test/TEST-21-SYSUSERS/test-1.expected-passwd +@@ -1 +1 @@ +-u1:x:222:222::/:/sbin/nologin ++u1:x:222:222::/:NOLOGIN +diff --git a/test/TEST-21-SYSUSERS/test-10.expected-passwd b/test/TEST-21-SYSUSERS/test-10.expected-passwd +index 222334b..ca2d764 100644 +--- a/test/TEST-21-SYSUSERS/test-10.expected-passwd ++++ b/test/TEST-21-SYSUSERS/test-10.expected-passwd +@@ -1,2 +1,2 @@ +-u1:x:300:300::/:/sbin/nologin +-u2:x:SYSTEM_UID_MAX:SYSTEM_UID_MAX::/:/sbin/nologin ++u1:x:300:300::/:NOLOGIN ++u2:x:SYSTEM_UID_MAX:SYSTEM_UID_MAX::/:NOLOGIN +diff --git a/test/TEST-21-SYSUSERS/test-11.expected-passwd b/test/TEST-21-SYSUSERS/test-11.expected-passwd +index 3f9ab39..737e43b 100644 +--- a/test/TEST-21-SYSUSERS/test-11.expected-passwd ++++ b/test/TEST-21-SYSUSERS/test-11.expected-passwd +@@ -2,5 +2,5 @@ root:x:0:0:root:/root:/bin/bash + systemd-network:x:492:492:Systemd Network Management:/:/usr/sbin/nologin + systemd-resolve:x:491:491:Systemd Resolver:/:/usr/sbin/nologin + systemd-timesync:x:493:493:Systemd Time Synchronization:/:/usr/sbin/nologin +-u1:x:222:222::/:/sbin/nologin ++u1:x:222:222::/:NOLOGIN + +:::::: +diff --git a/test/TEST-21-SYSUSERS/test-12.expected-passwd b/test/TEST-21-SYSUSERS/test-12.expected-passwd +index 75fe9b4..f076f3d 100644 +--- a/test/TEST-21-SYSUSERS/test-12.expected-passwd ++++ b/test/TEST-21-SYSUSERS/test-12.expected-passwd +@@ -1,2 +1,2 @@ + root:x:0:0:root:/root:/bin/bash +-systemd-coredump:x:1:1:systemd Core Dumper:/:/sbin/nologin ++systemd-coredump:x:1:1:systemd Core Dumper:/:NOLOGIN +diff --git a/test/TEST-21-SYSUSERS/test-2.expected-passwd b/test/TEST-21-SYSUSERS/test-2.expected-passwd +index 9eeee5d..af80688 100644 +--- a/test/TEST-21-SYSUSERS/test-2.expected-passwd ++++ b/test/TEST-21-SYSUSERS/test-2.expected-passwd +@@ -1,4 +1,4 @@ +-u1:x:SYSTEM_UID_MAX:SYSTEM_UID_MAX:some gecos:/random/dir:/sbin/nologin ++u1:x:SYSTEM_UID_MAX:SYSTEM_UID_MAX:some gecos:/random/dir:NOLOGIN + u2:x:777:777:some gecos:/random/dir:/bin/zsh + u3:x:778:778::/random/dir2:/bin/bash + u4:x:779:779::/:/bin/csh +diff --git a/test/TEST-21-SYSUSERS/test-3.expected-passwd b/test/TEST-21-SYSUSERS/test-3.expected-passwd +index a86954f..946303f 100644 +--- a/test/TEST-21-SYSUSERS/test-3.expected-passwd ++++ b/test/TEST-21-SYSUSERS/test-3.expected-passwd +@@ -1,4 +1,4 @@ +-foo:x:301:301::/:/sbin/nologin +-aaa:x:303:302::/:/sbin/nologin +-bbb:x:304:302::/:/sbin/nologin +-ccc:x:305:305::/:/sbin/nologin ++foo:x:301:301::/:NOLOGIN ++aaa:x:303:302::/:NOLOGIN ++bbb:x:304:302::/:NOLOGIN ++ccc:x:305:305::/:NOLOGIN +diff --git a/test/TEST-21-SYSUSERS/test-4.expected-passwd b/test/TEST-21-SYSUSERS/test-4.expected-passwd +index e0370a4..99d1048 100644 +--- a/test/TEST-21-SYSUSERS/test-4.expected-passwd ++++ b/test/TEST-21-SYSUSERS/test-4.expected-passwd +@@ -1,2 +1,2 @@ +-yyy:x:311:310::/:/sbin/nologin +-xxx:x:312:310::/:/sbin/nologin ++yyy:x:311:310::/:NOLOGIN ++xxx:x:312:310::/:NOLOGIN +diff --git a/test/TEST-21-SYSUSERS/test-5.expected-passwd b/test/TEST-21-SYSUSERS/test-5.expected-passwd +index 116b126..a83d566 100644 +--- a/test/TEST-21-SYSUSERS/test-5.expected-passwd ++++ b/test/TEST-21-SYSUSERS/test-5.expected-passwd +@@ -1,18 +1,18 @@ + root:x:0:0::/root:/bin/sh +-daemon:x:1:1::/usr/sbin:/sbin/nologin +-bin:x:2:2::/bin:/sbin/nologin +-sys:x:3:3::/dev:/sbin/nologin +-sync:x:4:65534::/bin:/sbin/nologin +-games:x:5:60::/usr/games:/sbin/nologin +-man:x:6:12::/var/cache/man:/sbin/nologin +-lp:x:7:7::/var/spool/lpd:/sbin/nologin +-mail:x:8:8::/var/mail:/sbin/nologin +-news:x:9:9::/var/spool/news:/sbin/nologin +-uucp:x:10:10::/var/spool/uucp:/sbin/nologin +-proxy:x:13:13::/bin:/sbin/nologin +-www-data:x:33:33::/var/www:/sbin/nologin +-backup:x:34:34::/var/backups:/sbin/nologin +-list:x:38:38::/var/list:/sbin/nologin +-irc:x:39:39::/var/run/ircd:/sbin/nologin +-gnats:x:41:41::/var/lib/gnats:/sbin/nologin +-nobody:x:65534:65534::/nonexistent:/sbin/nologin ++daemon:x:1:1::/usr/sbin:NOLOGIN ++bin:x:2:2::/bin:NOLOGIN ++sys:x:3:3::/dev:NOLOGIN ++sync:x:4:65534::/bin:NOLOGIN ++games:x:5:60::/usr/games:NOLOGIN ++man:x:6:12::/var/cache/man:NOLOGIN ++lp:x:7:7::/var/spool/lpd:NOLOGIN ++mail:x:8:8::/var/mail:NOLOGIN ++news:x:9:9::/var/spool/news:NOLOGIN ++uucp:x:10:10::/var/spool/uucp:NOLOGIN ++proxy:x:13:13::/bin:NOLOGIN ++www-data:x:33:33::/var/www:NOLOGIN ++backup:x:34:34::/var/backups:NOLOGIN ++list:x:38:38::/var/list:NOLOGIN ++irc:x:39:39::/var/run/ircd:NOLOGIN ++gnats:x:41:41::/var/lib/gnats:NOLOGIN ++nobody:x:65534:65534::/nonexistent:NOLOGIN +diff --git a/test/TEST-21-SYSUSERS/test-6.expected-passwd b/test/TEST-21-SYSUSERS/test-6.expected-passwd +index 5af9d11..ba55a13 100644 +--- a/test/TEST-21-SYSUSERS/test-6.expected-passwd ++++ b/test/TEST-21-SYSUSERS/test-6.expected-passwd +@@ -1 +1 @@ +-u1:x:SYSTEM_UID_MAX:SYSTEM_UID_MAX::/:/sbin/nologin ++u1:x:SYSTEM_UID_MAX:SYSTEM_UID_MAX::/:NOLOGIN +diff --git a/test/TEST-21-SYSUSERS/test-7.expected-passwd b/test/TEST-21-SYSUSERS/test-7.expected-passwd +index 79668c0..0c5d370 100644 +--- a/test/TEST-21-SYSUSERS/test-7.expected-passwd ++++ b/test/TEST-21-SYSUSERS/test-7.expected-passwd +@@ -1,5 +1,5 @@ +-bin:x:1:1::/:/sbin/nologin +-daemon:x:2:2::/:/sbin/nologin +-mail:x:8:12::/var/spool/mail:/sbin/nologin +-ftp:x:14:11::/srv/ftp:/sbin/nologin +-http:x:33:33::/srv/http:/sbin/nologin ++bin:x:1:1::/:NOLOGIN ++daemon:x:2:2::/:NOLOGIN ++mail:x:8:12::/var/spool/mail:NOLOGIN ++ftp:x:14:11::/srv/ftp:NOLOGIN ++http:x:33:33::/srv/http:NOLOGIN +diff --git a/test/TEST-21-SYSUSERS/test-8.expected-passwd b/test/TEST-21-SYSUSERS/test-8.expected-passwd +index 727b819..23e99f0 100644 +--- a/test/TEST-21-SYSUSERS/test-8.expected-passwd ++++ b/test/TEST-21-SYSUSERS/test-8.expected-passwd +@@ -1 +1 @@ +-username:x:SYSTEM_UID_MAX:300::/:/sbin/nologin ++username:x:SYSTEM_UID_MAX:300::/:NOLOGIN +diff --git a/test/TEST-21-SYSUSERS/test-9.expected-passwd b/test/TEST-21-SYSUSERS/test-9.expected-passwd +index a23260f..0bffbcd 100644 +--- a/test/TEST-21-SYSUSERS/test-9.expected-passwd ++++ b/test/TEST-21-SYSUSERS/test-9.expected-passwd +@@ -1,2 +1,2 @@ +-user1:x:300:300::/:/sbin/nologin +-user2:x:SYSTEM_UID_MAX:300::/:/sbin/nologin ++user1:x:300:300::/:NOLOGIN ++user2:x:SYSTEM_UID_MAX:300::/:NOLOGIN +diff --git a/test/TEST-21-SYSUSERS/test.sh b/test/TEST-21-SYSUSERS/test.sh +index b1049e7..809653c 100755 +--- a/test/TEST-21-SYSUSERS/test.sh ++++ b/test/TEST-21-SYSUSERS/test.sh +@@ -25,7 +25,14 @@ preprocess() { + # get this value from config.h, however the autopkgtest fails with + # it + SYSTEM_UID_MAX=$(awk 'BEGIN { uid=999 } /^\s*SYS_UID_MAX\s+/ { uid=$2 } END { print uid }' /etc/login.defs) +- sed "s/SYSTEM_UID_MAX/${SYSTEM_UID_MAX}/g" "$in" ++ ++ # we can't rely on config.h to get the nologin path, as autopkgtest ++ # uses pre-compiled binaries, so extract it from the systemd-sysusers ++ # binary which we are about to execute ++ NOLOGIN=$(strings $(type -p systemd-sysusers) | grep nologin) ++ ++ sed -e "s/SYSTEM_UID_MAX/${SYSTEM_UID_MAX}/g" \ ++ -e "s#NOLOGIN#${NOLOGIN}#g" "$in" + } + + compare() { diff --git a/debian/patches/missing-Add-new-Linux-capabilities.patch b/debian/patches/missing-Add-new-Linux-capabilities.patch new file mode 100644 index 0000000..324e024 --- /dev/null +++ b/debian/patches/missing-Add-new-Linux-capabilities.patch @@ -0,0 +1,36 @@ +From: =?utf-8?q?Michal_Koutn=C3=BD?= <mkoutny@suse.com> +Date: Wed, 24 Jun 2020 12:43:22 +0200 +Subject: missing: Add new Linux capabilities + +Linux kernel v5.8 adds two new capabilities. Make sure we can recognize +them even when built with an older kernel. + +(cherry picked from commit e41de5e491942b5391b1efb71c82ffd329b3d23d) +--- + src/basic/missing_capability.h | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/src/basic/missing_capability.h b/src/basic/missing_capability.h +index 1308a3d..dd6bccd 100644 +--- a/src/basic/missing_capability.h ++++ b/src/basic/missing_capability.h +@@ -10,3 +10,19 @@ + #undef CAP_LAST_CAP + #define CAP_LAST_CAP CAP_AUDIT_READ + #endif ++ ++/* 980737282232b752bb14dab96d77665c15889c36 (5.8) */ ++#ifndef CAP_PERFMON ++#define CAP_PERFMON 38 ++ ++#undef CAP_LAST_CAP ++#define CAP_LAST_CAP CAP_PERFMON ++#endif ++ ++/* a17b53c4a4b55ec322c132b6670743612229ee9c (5.8) */ ++#ifndef CAP_BPF ++#define CAP_BPF 39 ++ ++#undef CAP_LAST_CAP ++#define CAP_LAST_CAP CAP_BPF ++#endif diff --git a/debian/patches/mount-generators-do-not-make-unit-wanted-by-its-device-un.patch b/debian/patches/mount-generators-do-not-make-unit-wanted-by-its-device-un.patch new file mode 100644 index 0000000..d38962f --- /dev/null +++ b/debian/patches/mount-generators-do-not-make-unit-wanted-by-its-device-un.patch @@ -0,0 +1,58 @@ +From: Tom Yan <tom.ty89@gmail.com> +Date: Wed, 9 Jan 2019 23:35:24 +0800 +Subject: mount/generators: do not make unit wanted by its device unit + +As device units will be reloaded by systemd whenever the corresponding device generates a "changed" event, if the mount unit / cryptsetup service is wanted by its device unit, the former can be restarted by systemd unexpectedly after the user stopped them explicitly. It is not sensible at all and can be considered dangerous. Neither is the behaviour conventional (as `auto` in fstab should only affect behaviour on boot and `mount -a`) or ever documented at all (not even in systemd, see systemd.mount(5) and crypttab(5)). + +(cherry picked from commit 142b8142d7bb84f07ac33fc00527a4d48ac8ef9f) +--- + src/core/mount.c | 6 +----- + src/cryptsetup/cryptsetup-generator.c | 4 ---- + 2 files changed, 1 insertion(+), 9 deletions(-) + +diff --git a/src/core/mount.c b/src/core/mount.c +index c31cad6..7064fa1 100644 +--- a/src/core/mount.c ++++ b/src/core/mount.c +@@ -338,7 +338,6 @@ static int mount_add_mount_dependencies(Mount *m) { + } + + static int mount_add_device_dependencies(Mount *m) { +- bool device_wants_mount; + UnitDependencyMask mask; + MountParameters *p; + UnitDependency dep; +@@ -368,9 +367,6 @@ static int mount_add_device_dependencies(Mount *m) { + if (path_equal(m->where, "/")) + return 0; + +- device_wants_mount = +- mount_is_auto(p) && !mount_is_automount(p) && MANAGER_IS_SYSTEM(UNIT(m)->manager); +- + /* Mount units from /proc/self/mountinfo are not bound to devices + * by default since they're subject to races when devices are + * unplugged. But the user can still force this dep with an +@@ -381,7 +377,7 @@ static int mount_add_device_dependencies(Mount *m) { + /* We always use 'what' from /proc/self/mountinfo if mounted */ + mask = m->from_proc_self_mountinfo ? UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT : UNIT_DEPENDENCY_FILE; + +- r = unit_add_node_dependency(UNIT(m), p->what, device_wants_mount, dep, mask); ++ r = unit_add_node_dependency(UNIT(m), p->what, false, dep, mask); + if (r < 0) + return r; + +diff --git a/src/cryptsetup/cryptsetup-generator.c b/src/cryptsetup/cryptsetup-generator.c +index 8759a26..ea18e84 100644 +--- a/src/cryptsetup/cryptsetup-generator.c ++++ b/src/cryptsetup/cryptsetup-generator.c +@@ -287,10 +287,6 @@ static int create_disk( + return log_error_errno(r, "Failed to write unit file %s: %m", n); + + if (!noauto) { +- r = generator_add_symlink(arg_dest, d, "wants", n); +- if (r < 0) +- return r; +- + r = generator_add_symlink(arg_dest, + netdev ? "remote-cryptsetup.target" : "cryptsetup.target", + nofail ? "wants" : "requires", n); diff --git a/debian/patches/mount-remove-unused-mount_is_auto-and-mount_is_automount.patch b/debian/patches/mount-remove-unused-mount_is_auto-and-mount_is_automount.patch new file mode 100644 index 0000000..58acfc8 --- /dev/null +++ b/debian/patches/mount-remove-unused-mount_is_auto-and-mount_is_automount.patch @@ -0,0 +1,34 @@ +From: Tom Yan <tom.ty89@gmail.com> +Date: Thu, 10 Jan 2019 00:19:43 +0800 +Subject: mount: remove unused mount_is_auto and mount_is_automount + +(cherry picked from commit d0fe45cb151774827a3aca4ea5a19856dec9f600) +--- + src/core/mount.c | 14 -------------- + 1 file changed, 14 deletions(-) + +diff --git a/src/core/mount.c b/src/core/mount.c +index 7064fa1..8da818b 100644 +--- a/src/core/mount.c ++++ b/src/core/mount.c +@@ -101,20 +101,6 @@ static bool mount_is_bind(const MountParameters *p) { + return false; + } + +-static bool mount_is_auto(const MountParameters *p) { +- assert(p); +- +- return !fstab_test_option(p->options, "noauto\0"); +-} +- +-static bool mount_is_automount(const MountParameters *p) { +- assert(p); +- +- return fstab_test_option(p->options, +- "comment=systemd.automount\0" +- "x-systemd.automount\0"); +-} +- + static bool mount_is_bound_to_device(const Mount *m) { + const MountParameters *p; + diff --git a/debian/patches/namespace-make-MountFlags-shared-work-again.patch b/debian/patches/namespace-make-MountFlags-shared-work-again.patch new file mode 100644 index 0000000..2954e67 --- /dev/null +++ b/debian/patches/namespace-make-MountFlags-shared-work-again.patch @@ -0,0 +1,58 @@ +From: Franck Bui <fbui@suse.com> +Date: Wed, 13 Feb 2019 18:45:36 +0100 +Subject: namespace: make MountFlags=shared work again + +Since commit 0722b359342d2a9f9e0d453875624387a0ba1be2, the root mountpoint is +unconditionnally turned to slave which breaks units that are using explicitly +MountFlags=shared (and no other options that would implicitly require a slave +root mountpoint). + +Here is a test case: + + $ systemctl cat test-shared-mount-flag.service + # /etc/systemd/system/test-shared-mount-flag.service + [Service] + Type=simple + ExecStartPre=/usr/bin/mkdir -p /mnt/tmp + ExecStart=/bin/sh -c "/usr/bin/mount -t tmpfs -o size=10M none /mnt/tmp && sleep infinity" + ExecStop=-/bin/sh -c "/usr/bin/umount /mnt/tmp" + MountFlags=shared + + $ systemctl start test-shared-mount-flag.service + $ findmnt /mnt/tmp + $ + +Mount on /mnt/tmp is not visible from the host although MountFlags=shared was +used. + +This patch fixes that and turns the root mountpoint to slave when it's really +required. + +(cherry picked from commit 37ed15d7edaf59a1fc7c9e3552cd93a83f3814ef) +--- + src/core/execute.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/src/core/execute.c b/src/core/execute.c +index 47518f4..f2a4c54 100644 +--- a/src/core/execute.c ++++ b/src/core/execute.c +@@ -1839,7 +1839,7 @@ static bool exec_needs_mount_namespace( + if (context->n_temporary_filesystems > 0) + return true; + +- if (context->mount_flags != 0) ++ if (!IN_SET(context->mount_flags, 0, MS_SHARED)) + return true; + + if (context->private_tmp && runtime && (runtime->tmp_dir || runtime->var_tmp_dir)) +@@ -2435,6 +2435,9 @@ static int apply_mount_namespace( + else + ns_info = (NamespaceInfo) {}; + ++ if (context->mount_flags == MS_SHARED) ++ log_unit_debug(u, "shared mount propagation hidden by other fs namespacing unit settings: ignoring"); ++ + r = setup_namespace(root_dir, root_image, + &ns_info, context->read_write_paths, + needs_sandboxing ? context->read_only_paths : NULL, diff --git a/debian/patches/network-check-whether-ipv6-is-enabled-in-sysctl.patch b/debian/patches/network-check-whether-ipv6-is-enabled-in-sysctl.patch new file mode 100644 index 0000000..2b65530 --- /dev/null +++ b/debian/patches/network-check-whether-ipv6-is-enabled-in-sysctl.patch @@ -0,0 +1,119 @@ +From: Yu Watanabe <watanabe.yu+github@gmail.com> +Date: Mon, 18 Feb 2019 15:00:15 +0900 +Subject: network: check whether ipv6 is enabled in sysctl + +Currently, the value is read only once. + +Fixes #11711. + +(cherry picked from commit 4b600505dda8af6c43496f9e93e420a192d9a38b) +--- + src/network/networkd-link.c | 12 ++++++++++++ + src/network/networkd-manager.c | 18 ++++++++++++++++++ + src/network/networkd-manager.h | 4 ++++ + 3 files changed, 34 insertions(+) + +diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c +index 22392d7..322e701 100644 +--- a/src/network/networkd-link.c ++++ b/src/network/networkd-link.c +@@ -51,6 +51,9 @@ static bool link_dhcp6_enabled(Link *link) { + if (!link->network) + return false; + ++ if (manager_sysctl_ipv6_enabled(link->manager) == 0) ++ return false; ++ + return link->network->dhcp & ADDRESS_FAMILY_IPV6; + } + +@@ -108,6 +111,9 @@ static bool link_ipv6ll_enabled(Link *link) { + if (streq_ptr(link->kind, "wireguard")) + return false; + ++ if (manager_sysctl_ipv6_enabled(link->manager) == 0) ++ return false; ++ + return link->network->link_local & ADDRESS_FAMILY_IPV6; + } + +@@ -120,6 +126,9 @@ static bool link_ipv6_enabled(Link *link) { + if (link->network->bridge) + return false; + ++ if (manager_sysctl_ipv6_enabled(link->manager) == 0) ++ return false; ++ + /* DHCPv6 client will not be started if no IPv6 link-local address is configured. */ + return link_ipv6ll_enabled(link) || network_has_static_ipv6_addresses(link->network); + } +@@ -199,6 +208,9 @@ static bool link_ipv6_forward_enabled(Link *link) { + if (link->network->ip_forward == _ADDRESS_FAMILY_BOOLEAN_INVALID) + return false; + ++ if (manager_sysctl_ipv6_enabled(link->manager) == 0) ++ return false; ++ + return link->network->ip_forward & ADDRESS_FAMILY_IPV6; + } + +diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c +index c8d369e..f32bc7f 100644 +--- a/src/network/networkd-manager.c ++++ b/src/network/networkd-manager.c +@@ -23,6 +23,7 @@ + #include "path-util.h" + #include "set.h" + #include "strv.h" ++#include "sysctl-util.h" + #include "tmpfile-util.h" + #include "virt.h" + +@@ -1360,6 +1361,8 @@ int manager_new(Manager **ret) { + if (!m->state_file) + return -ENOMEM; + ++ m->sysctl_ipv6_enabled = -1; ++ + r = sd_event_default(&m->event); + if (r < 0) + return r; +@@ -1858,3 +1861,18 @@ int manager_request_product_uuid(Manager *m, Link *link) { + + return 0; + } ++ ++int manager_sysctl_ipv6_enabled(Manager *manager) { ++ _cleanup_free_ char *value = NULL; ++ int r; ++ ++ if (manager->sysctl_ipv6_enabled >= 0) ++ return manager->sysctl_ipv6_enabled; ++ ++ r = sysctl_read_ip_property(AF_INET6, "all", "disable_ipv6", &value); ++ if (r < 0) ++ return log_warning_errno(r, "Failed to read net.ipv6.conf.all.disable_ipv6 sysctl property: %m"); ++ ++ manager->sysctl_ipv6_enabled = value[0] == '0'; ++ return manager->sysctl_ipv6_enabled; ++} +diff --git a/src/network/networkd-manager.h b/src/network/networkd-manager.h +index 289ca96..d292d76 100644 +--- a/src/network/networkd-manager.h ++++ b/src/network/networkd-manager.h +@@ -58,6 +58,8 @@ struct Manager { + Set *rules; + Set *rules_foreign; + Set *rules_saved; ++ ++ int sysctl_ipv6_enabled; + }; + + extern const sd_bus_vtable manager_vtable[]; +@@ -95,4 +97,6 @@ Link *manager_dhcp6_prefix_get(Manager *m, struct in6_addr *addr); + int manager_dhcp6_prefix_add(Manager *m, struct in6_addr *addr, Link *link); + int manager_dhcp6_prefix_remove_all(Manager *m, Link *link); + ++int manager_sysctl_ipv6_enabled(Manager *manager); ++ + DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free); diff --git a/debian/patches/network-do-not-remove-rule-when-it-is-requested-by-existi.patch b/debian/patches/network-do-not-remove-rule-when-it-is-requested-by-existi.patch new file mode 100644 index 0000000..19cabfe --- /dev/null +++ b/debian/patches/network-do-not-remove-rule-when-it-is-requested-by-existi.patch @@ -0,0 +1,56 @@ +From: Yu Watanabe <watanabe.yu+github@gmail.com> +Date: Fri, 22 Feb 2019 13:32:47 +0900 +Subject: network: do not remove rule when it is requested by existing links + +Otherwise, the first link once removes all saved rules in the foreign +rule database, and the second or later links create again... + +(cherry picked from commit 031fb59a984e5b51f3c72aa8125ecc50b08011fe) +--- + src/network/networkd-routing-policy-rule.c | 26 ++++++++++++++++++++++++++ + 1 file changed, 26 insertions(+) + +diff --git a/src/network/networkd-routing-policy-rule.c b/src/network/networkd-routing-policy-rule.c +index 21a40fa..65a9af2 100644 +--- a/src/network/networkd-routing-policy-rule.c ++++ b/src/network/networkd-routing-policy-rule.c +@@ -1250,6 +1250,26 @@ int routing_policy_load_rules(const char *state_file, Set **rules) { + return 0; + } + ++static bool manager_links_have_routing_policy_rule(Manager *m, RoutingPolicyRule *rule) { ++ RoutingPolicyRule *link_rule; ++ Iterator i; ++ Link *link; ++ ++ assert(m); ++ assert(rule); ++ ++ HASHMAP_FOREACH(link, m->links, i) { ++ if (!link->network) ++ continue; ++ ++ LIST_FOREACH(rules, link_rule, link->network->rules) ++ if (routing_policy_rule_compare_func(link_rule, rule) == 0) ++ return true; ++ } ++ ++ return false; ++} ++ + void routing_policy_rule_purge(Manager *m, Link *link) { + RoutingPolicyRule *rule, *existing; + Iterator i; +@@ -1263,6 +1283,12 @@ void routing_policy_rule_purge(Manager *m, Link *link) { + if (!existing) + continue; /* Saved rule does not exist anymore. */ + ++ if (manager_links_have_routing_policy_rule(m, existing)) ++ continue; /* Existing links have the saved rule. */ ++ ++ /* Existing links do not have the saved rule. Let's drop the rule now, and re-configure it ++ * later when it is requested. */ ++ + r = routing_policy_rule_remove(existing, link, NULL); + if (r < 0) { + log_warning_errno(r, "Could not remove routing policy rules: %m"); diff --git a/debian/patches/network-do-not-send-ipv6-token-to-kernel.patch b/debian/patches/network-do-not-send-ipv6-token-to-kernel.patch new file mode 100644 index 0000000..766d470 --- /dev/null +++ b/debian/patches/network-do-not-send-ipv6-token-to-kernel.patch @@ -0,0 +1,92 @@ +From: Yu Watanabe <watanabe.yu+github@gmail.com> +Date: Thu, 9 May 2019 14:39:46 +0900 +Subject: network: do not send ipv6 token to kernel + +We disabled kernel RA support. Then, we should not send +IFLA_INET6_TOKEN. +Thus, we do not need to send IFLA_INET6_ADDR_GEN_MODE twice. + +Follow-up for 0e2fdb83bb5e22047e0c7cc058b415d0e93f02cf and +4eb086a38712ea98faf41e075b84555b11b54362. + +(cherry picked from commit 9f6e82e6eb3b6e73d66d00d1d6eee60691fb702f) +--- + src/network/networkd-link.c | 51 ++++++--------------------------------------- + 1 file changed, 6 insertions(+), 45 deletions(-) + +diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c +index 6445b94..ac76c86 100644 +--- a/src/network/networkd-link.c ++++ b/src/network/networkd-link.c +@@ -1816,6 +1816,9 @@ static int link_configure_addrgen_mode(Link *link) { + assert(link->manager); + assert(link->manager->rtnl); + ++ if (!socket_ipv6_is_supported()) ++ return 0; ++ + log_link_debug(link, "Setting address genmode for link"); + + r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex); +@@ -1917,46 +1920,6 @@ static int link_up(Link *link) { + return log_link_error_errno(link, r, "Could not set MAC address: %m"); + } + +- if (link_ipv6_enabled(link)) { +- uint8_t ipv6ll_mode; +- +- r = sd_netlink_message_open_container(req, IFLA_AF_SPEC); +- if (r < 0) +- return log_link_error_errno(link, r, "Could not open IFLA_AF_SPEC container: %m"); +- +- /* if the kernel lacks ipv6 support setting IFF_UP fails if any ipv6 options are passed */ +- r = sd_netlink_message_open_container(req, AF_INET6); +- if (r < 0) +- return log_link_error_errno(link, r, "Could not open AF_INET6 container: %m"); +- +- if (!in_addr_is_null(AF_INET6, &link->network->ipv6_token)) { +- r = sd_netlink_message_append_in6_addr(req, IFLA_INET6_TOKEN, &link->network->ipv6_token.in6); +- if (r < 0) +- return log_link_error_errno(link, r, "Could not append IFLA_INET6_TOKEN: %m"); +- } +- +- if (!link_ipv6ll_enabled(link)) +- ipv6ll_mode = IN6_ADDR_GEN_MODE_NONE; +- else if (sysctl_read_ip_property(AF_INET6, link->ifname, "stable_secret", NULL) < 0) +- /* The file may not exist. And event if it exists, when stable_secret is unset, +- * reading the file fails with EIO. */ +- ipv6ll_mode = IN6_ADDR_GEN_MODE_EUI64; +- else +- ipv6ll_mode = IN6_ADDR_GEN_MODE_STABLE_PRIVACY; +- +- r = sd_netlink_message_append_u8(req, IFLA_INET6_ADDR_GEN_MODE, ipv6ll_mode); +- if (r < 0) +- return log_link_error_errno(link, r, "Could not append IFLA_INET6_ADDR_GEN_MODE: %m"); +- +- r = sd_netlink_message_close_container(req); +- if (r < 0) +- return log_link_error_errno(link, r, "Could not close AF_INET6 container: %m"); +- +- r = sd_netlink_message_close_container(req); +- if (r < 0) +- return log_link_error_errno(link, r, "Could not close IFLA_AF_SPEC container: %m"); +- } +- + r = netlink_call_async(link->manager->rtnl, NULL, req, link_up_handler, + link_netlink_destroy_callback, link); + if (r < 0) +@@ -3044,11 +3007,9 @@ static int link_configure(Link *link) { + return r; + } + +- if (socket_ipv6_is_supported()) { +- r = link_configure_addrgen_mode(link); +- if (r < 0) +- return r; +- } ++ r = link_configure_addrgen_mode(link); ++ if (r < 0) ++ return r; + + return link_configure_after_setting_mtu(link); + } diff --git a/debian/patches/network-ignore-requested-ipv6-addresses-when-ipv6-is-disa.patch b/debian/patches/network-ignore-requested-ipv6-addresses-when-ipv6-is-disa.patch new file mode 100644 index 0000000..5b6ea17 --- /dev/null +++ b/debian/patches/network-ignore-requested-ipv6-addresses-when-ipv6-is-disa.patch @@ -0,0 +1,67 @@ +From: Yu Watanabe <watanabe.yu+github@gmail.com> +Date: Tue, 11 Jun 2019 23:20:56 +0900 +Subject: network: ignore requested ipv6 addresses when ipv6 is disabled by + sysctl + +(cherry picked from commit 54a1a535bd60f13964bbddd8f381601e33e8e56f) +--- + src/network/networkd-address.c | 7 ++++++- + src/network/networkd-link.c | 4 ++-- + src/network/networkd-ndisc.c | 4 ++-- + 3 files changed, 10 insertions(+), 5 deletions(-) + +diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c +index 3cdbd9e..a9f65e5 100644 +--- a/src/network/networkd-address.c ++++ b/src/network/networkd-address.c +@@ -565,6 +565,11 @@ int address_configure( + assert(link->manager->rtnl); + assert(callback); + ++ if (address->family == AF_INET6 && manager_sysctl_ipv6_enabled(link->manager) == 0) { ++ log_link_warning(link, "An IPv6 address is requested, but IPv6 is disabled by sysctl, ignoring."); ++ return 0; ++ } ++ + /* If this is a new address, then refuse adding more than the limit */ + if (address_get(link, address->family, &address->in_addr, address->prefixlen, NULL) <= 0 && + set_size(link->addresses) >= ADDRESSES_PER_LINK_MAX) +@@ -669,7 +674,7 @@ int address_configure( + return log_error_errno(r, "Could not add address: %m"); + } + +- return 0; ++ return 1; + } + + int config_parse_broadcast( +diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c +index 322e701..638aae0 100644 +--- a/src/network/networkd-link.c ++++ b/src/network/networkd-link.c +@@ -1123,8 +1123,8 @@ static int link_request_set_addresses(Link *link) { + link_enter_failed(link); + return r; + } +- +- link->address_messages++; ++ if (r > 0) ++ link->address_messages++; + } + + LIST_FOREACH(labels, label, link->network->address_labels) { +diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c +index e5b8d11..78c98a0 100644 +--- a/src/network/networkd-ndisc.c ++++ b/src/network/networkd-ndisc.c +@@ -205,8 +205,8 @@ static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *r + link_enter_failed(link); + return r; + } +- +- link->ndisc_messages++; ++ if (r > 0) ++ link->ndisc_messages++; + + return 0; + } diff --git a/debian/patches/network-ignore-requested-ipv6-route-when-ipv6-is-disabled.patch b/debian/patches/network-ignore-requested-ipv6-route-when-ipv6-is-disabled.patch new file mode 100644 index 0000000..0960802 --- /dev/null +++ b/debian/patches/network-ignore-requested-ipv6-route-when-ipv6-is-disabled.patch @@ -0,0 +1,88 @@ +From: Yu Watanabe <watanabe.yu+github@gmail.com> +Date: Tue, 11 Jun 2019 23:26:11 +0900 +Subject: network: ignore requested ipv6 route when ipv6 is disabled by sysctl + +(cherry picked from commit c442331750a2a9711036080f7590e190b9b0eb54) +--- + src/network/networkd-link.c | 4 ++-- + src/network/networkd-ndisc.c | 12 ++++++------ + src/network/networkd-route.c | 7 ++++++- + 3 files changed, 14 insertions(+), 9 deletions(-) + +diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c +index 638aae0..5a181c2 100644 +--- a/src/network/networkd-link.c ++++ b/src/network/networkd-link.c +@@ -840,8 +840,8 @@ static int link_request_set_routes(Link *link) { + link_enter_failed(link); + return r; + } +- +- link->route_messages++; ++ if (r > 0) ++ link->route_messages++; + } + + if (link->route_messages == 0) { +diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c +index 78c98a0..36fbe29 100644 +--- a/src/network/networkd-ndisc.c ++++ b/src/network/networkd-ndisc.c +@@ -117,8 +117,8 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) { + link_enter_failed(link); + return r; + } +- +- link->ndisc_messages++; ++ if (r > 0) ++ link->ndisc_messages++; + + return 0; + } +@@ -255,8 +255,8 @@ static int ndisc_router_process_onlink_prefix(Link *link, sd_ndisc_router *rt) { + link_enter_failed(link); + return r; + } +- +- link->ndisc_messages++; ++ if (r > 0) ++ link->ndisc_messages++; + + return 0; + } +@@ -316,8 +316,8 @@ static int ndisc_router_process_route(Link *link, sd_ndisc_router *rt) { + link_enter_failed(link); + return r; + } +- +- link->ndisc_messages++; ++ if (r > 0) ++ link->ndisc_messages++; + + return 0; + } +diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c +index 5553a7e..5b7e019 100644 +--- a/src/network/networkd-route.c ++++ b/src/network/networkd-route.c +@@ -509,6 +509,11 @@ int route_configure( + assert(IN_SET(route->family, AF_INET, AF_INET6)); + assert(callback); + ++ if (route->family == AF_INET6 && manager_sysctl_ipv6_enabled(link->manager) == 0) { ++ log_link_warning(link, "An IPv6 route is requested, but IPv6 is disabled by sysctl, ignoring."); ++ return 0; ++ } ++ + if (route_get(link, route->family, &route->dst, route->dst_prefixlen, route->tos, route->priority, route->table, NULL) <= 0 && + set_size(link->routes) >= routes_max()) + return -E2BIG; +@@ -675,7 +680,7 @@ int route_configure( + sd_event_source_unref(route->expire); + route->expire = TAKE_PTR(expire); + +- return 0; ++ return 1; + } + + int config_parse_gateway( diff --git a/debian/patches/network-ignore-requested-ipv6-routing-policy-rule-when-ip.patch b/debian/patches/network-ignore-requested-ipv6-routing-policy-rule-when-ip.patch new file mode 100644 index 0000000..270af9c --- /dev/null +++ b/debian/patches/network-ignore-requested-ipv6-routing-policy-rule-when-ip.patch @@ -0,0 +1,51 @@ +From: Yu Watanabe <watanabe.yu+github@gmail.com> +Date: Tue, 11 Jun 2019 23:29:57 +0900 +Subject: network: ignore requested ipv6 routing policy rule when ipv6 is + disabled by sysctl + +(cherry picked from commit 7ef7e5509b637e660e89ba8a938930ec01de6e54) +--- + src/network/networkd-link.c | 4 ++-- + src/network/networkd-routing-policy-rule.c | 7 ++++++- + 2 files changed, 8 insertions(+), 3 deletions(-) + +diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c +index 5a181c2..13852af 100644 +--- a/src/network/networkd-link.c ++++ b/src/network/networkd-link.c +@@ -765,8 +765,8 @@ static int link_request_set_routing_policy_rule(Link *link) { + link_enter_failed(link); + return r; + } +- +- link->routing_policy_rule_messages++; ++ if (r > 0) ++ link->routing_policy_rule_messages++; + } + + routing_policy_rule_purge(link->manager, link); +diff --git a/src/network/networkd-routing-policy-rule.c b/src/network/networkd-routing-policy-rule.c +index 65a9af2..0b62a0e 100644 +--- a/src/network/networkd-routing-policy-rule.c ++++ b/src/network/networkd-routing-policy-rule.c +@@ -492,6 +492,11 @@ int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link, link_netl + assert(link->manager); + assert(link->manager->rtnl); + ++ if (rule->family == AF_INET6 && manager_sysctl_ipv6_enabled(link->manager) == 0) { ++ log_link_warning(link, "An IPv6 routing policy rule is requested, but IPv6 is disabled by sysctl, ignoring."); ++ return 0; ++ } ++ + r = sd_rtnl_message_new_routing_policy_rule(link->manager->rtnl, &m, RTM_NEWRULE, rule->family); + if (r < 0) + return log_error_errno(r, "Could not allocate RTM_NEWRULE message: %m"); +@@ -609,7 +614,7 @@ int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link, link_netl + if (r < 0) + return log_error_errno(r, "Could not add rule: %m"); + +- return 0; ++ return 1; + } + + static int parse_fwmark_fwmask(const char *s, uint32_t *fwmark, uint32_t *fwmask) { diff --git a/debian/patches/network-read-link-specific-sysctl-value.patch b/debian/patches/network-read-link-specific-sysctl-value.patch new file mode 100644 index 0000000..aaa29a6 --- /dev/null +++ b/debian/patches/network-read-link-specific-sysctl-value.patch @@ -0,0 +1,208 @@ +From: Yu Watanabe <watanabe.yu+github@gmail.com> +Date: Fri, 14 Jun 2019 09:42:51 +0900 +Subject: network: read link specific sysctl value + +This introduce link_sysctl_ipv6_enabled() and replaces +manager_sysctl_ipv6_enabled() with it. + +(cherry picked from commit bafa9641446852f7fa15ca12d08a223d345c78ea) +--- + src/network/networkd-address.c | 2 +- + src/network/networkd-link.c | 24 ++++++++++++++++++++---- + src/network/networkd-link.h | 4 ++++ + src/network/networkd-manager.c | 17 ----------------- + src/network/networkd-manager.h | 4 ---- + src/network/networkd-route.c | 2 +- + src/network/networkd-routing-policy-rule.c | 2 +- + 7 files changed, 27 insertions(+), 28 deletions(-) + +diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c +index a9f65e5..e0ee896 100644 +--- a/src/network/networkd-address.c ++++ b/src/network/networkd-address.c +@@ -565,7 +565,7 @@ int address_configure( + assert(link->manager->rtnl); + assert(callback); + +- if (address->family == AF_INET6 && manager_sysctl_ipv6_enabled(link->manager) == 0) { ++ if (address->family == AF_INET6 && link_sysctl_ipv6_enabled(link) == 0) { + log_link_warning(link, "An IPv6 address is requested, but IPv6 is disabled by sysctl, ignoring."); + return 0; + } +diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c +index 13852af..3cfdf4a 100644 +--- a/src/network/networkd-link.c ++++ b/src/network/networkd-link.c +@@ -28,6 +28,7 @@ + #include "stdio-util.h" + #include "string-table.h" + #include "strv.h" ++#include "sysctl-util.h" + #include "tmpfile-util.h" + #include "util.h" + #include "virt.h" +@@ -39,6 +40,20 @@ DUID* link_get_duid(Link *link) { + return &link->manager->duid; + } + ++int link_sysctl_ipv6_enabled(Link *link) { ++ _cleanup_free_ char *value = NULL; ++ int r; ++ ++ r = sysctl_read_ip_property(AF_INET6, link->ifname, "disable_ipv6", &value); ++ if (r < 0) ++ return log_link_warning_errno(link, r, ++ "Failed to read net.ipv6.conf.%s.disable_ipv6 sysctl property: %m", ++ link->ifname); ++ ++ link->sysctl_ipv6_enabled = value[0] == '0'; ++ return link->sysctl_ipv6_enabled; ++} ++ + static bool link_dhcp6_enabled(Link *link) { + assert(link); + +@@ -51,7 +66,7 @@ static bool link_dhcp6_enabled(Link *link) { + if (!link->network) + return false; + +- if (manager_sysctl_ipv6_enabled(link->manager) == 0) ++ if (link_sysctl_ipv6_enabled(link) == 0) + return false; + + return link->network->dhcp & ADDRESS_FAMILY_IPV6; +@@ -111,7 +126,7 @@ static bool link_ipv6ll_enabled(Link *link) { + if (streq_ptr(link->kind, "wireguard")) + return false; + +- if (manager_sysctl_ipv6_enabled(link->manager) == 0) ++ if (link_sysctl_ipv6_enabled(link) == 0) + return false; + + return link->network->link_local & ADDRESS_FAMILY_IPV6; +@@ -126,7 +141,7 @@ static bool link_ipv6_enabled(Link *link) { + if (link->network->bridge) + return false; + +- if (manager_sysctl_ipv6_enabled(link->manager) == 0) ++ if (link_sysctl_ipv6_enabled(link) == 0) + return false; + + /* DHCPv6 client will not be started if no IPv6 link-local address is configured. */ +@@ -208,7 +223,7 @@ static bool link_ipv6_forward_enabled(Link *link) { + if (link->network->ip_forward == _ADDRESS_FAMILY_BOOLEAN_INVALID) + return false; + +- if (manager_sysctl_ipv6_enabled(link->manager) == 0) ++ if (link_sysctl_ipv6_enabled(link) == 0) + return false; + + return link->network->ip_forward & ADDRESS_FAMILY_IPV6; +@@ -476,6 +491,7 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) { + .rtnl_extended_attrs = true, + .ifindex = ifindex, + .iftype = iftype, ++ .sysctl_ipv6_enabled = -1, + }; + + link->ifname = strdup(ifname); +diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h +index dcb1ea6..6adea64 100644 +--- a/src/network/networkd-link.h ++++ b/src/network/networkd-link.h +@@ -128,6 +128,8 @@ typedef struct Link { + + Hashmap *bound_by_links; + Hashmap *bound_to_links; ++ ++ int sysctl_ipv6_enabled; + } Link; + + typedef int (*link_netlink_message_handler_t)(sd_netlink*, sd_netlink_message*, Link*); +@@ -209,6 +211,8 @@ int link_send_changed(Link *link, const char *property, ...) _sentinel_; + #define LOG_LINK_MESSAGE(link, fmt, ...) "MESSAGE=%s: " fmt, (link)->ifname, ##__VA_ARGS__ + #define LOG_LINK_INTERFACE(link) "INTERFACE=%s", (link)->ifname + ++int link_sysctl_ipv6_enabled(Link *link); ++ + #define ADDRESS_FMT_VAL(address) \ + be32toh((address).s_addr) >> 24, \ + (be32toh((address).s_addr) >> 16) & 0xFFu, \ +diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c +index f32bc7f..acb9a75 100644 +--- a/src/network/networkd-manager.c ++++ b/src/network/networkd-manager.c +@@ -1361,8 +1361,6 @@ int manager_new(Manager **ret) { + if (!m->state_file) + return -ENOMEM; + +- m->sysctl_ipv6_enabled = -1; +- + r = sd_event_default(&m->event); + if (r < 0) + return r; +@@ -1861,18 +1859,3 @@ int manager_request_product_uuid(Manager *m, Link *link) { + + return 0; + } +- +-int manager_sysctl_ipv6_enabled(Manager *manager) { +- _cleanup_free_ char *value = NULL; +- int r; +- +- if (manager->sysctl_ipv6_enabled >= 0) +- return manager->sysctl_ipv6_enabled; +- +- r = sysctl_read_ip_property(AF_INET6, "all", "disable_ipv6", &value); +- if (r < 0) +- return log_warning_errno(r, "Failed to read net.ipv6.conf.all.disable_ipv6 sysctl property: %m"); +- +- manager->sysctl_ipv6_enabled = value[0] == '0'; +- return manager->sysctl_ipv6_enabled; +-} +diff --git a/src/network/networkd-manager.h b/src/network/networkd-manager.h +index d292d76..289ca96 100644 +--- a/src/network/networkd-manager.h ++++ b/src/network/networkd-manager.h +@@ -58,8 +58,6 @@ struct Manager { + Set *rules; + Set *rules_foreign; + Set *rules_saved; +- +- int sysctl_ipv6_enabled; + }; + + extern const sd_bus_vtable manager_vtable[]; +@@ -97,6 +95,4 @@ Link *manager_dhcp6_prefix_get(Manager *m, struct in6_addr *addr); + int manager_dhcp6_prefix_add(Manager *m, struct in6_addr *addr, Link *link); + int manager_dhcp6_prefix_remove_all(Manager *m, Link *link); + +-int manager_sysctl_ipv6_enabled(Manager *manager); +- + DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free); +diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c +index 5b7e019..67b0ab4 100644 +--- a/src/network/networkd-route.c ++++ b/src/network/networkd-route.c +@@ -509,7 +509,7 @@ int route_configure( + assert(IN_SET(route->family, AF_INET, AF_INET6)); + assert(callback); + +- if (route->family == AF_INET6 && manager_sysctl_ipv6_enabled(link->manager) == 0) { ++ if (route->family == AF_INET6 && link_sysctl_ipv6_enabled(link) == 0) { + log_link_warning(link, "An IPv6 route is requested, but IPv6 is disabled by sysctl, ignoring."); + return 0; + } +diff --git a/src/network/networkd-routing-policy-rule.c b/src/network/networkd-routing-policy-rule.c +index 0b62a0e..2378ed2 100644 +--- a/src/network/networkd-routing-policy-rule.c ++++ b/src/network/networkd-routing-policy-rule.c +@@ -492,7 +492,7 @@ int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link, link_netl + assert(link->manager); + assert(link->manager->rtnl); + +- if (rule->family == AF_INET6 && manager_sysctl_ipv6_enabled(link->manager) == 0) { ++ if (rule->family == AF_INET6 && link_sysctl_ipv6_enabled(link) == 0) { + log_link_warning(link, "An IPv6 routing policy rule is requested, but IPv6 is disabled by sysctl, ignoring."); + return 0; + } diff --git a/debian/patches/network-remove-routing-policy-rule-from-foreign-rule-data.patch b/debian/patches/network-remove-routing-policy-rule-from-foreign-rule-data.patch new file mode 100644 index 0000000..b19e588 --- /dev/null +++ b/debian/patches/network-remove-routing-policy-rule-from-foreign-rule-data.patch @@ -0,0 +1,52 @@ +From: Yu Watanabe <watanabe.yu+github@gmail.com> +Date: Fri, 22 Feb 2019 13:27:44 +0900 +Subject: network: remove routing policy rule from foreign rule database when + it is removed + +Previously, When the first link configures rules, it removes all saved +rules, which were configured by networkd previously, in the foreign rule +database, but the rules themselves are still in the database. +Thus, when the second or later link configures rules, it errnously +treats the rules already exist. +This is the root of issue #11280. + +This removes rules from the foreign database when they are removed. + +Fixes #11280. + +(cherry picked from commit 92cd00b9749141907a1110044cc7d1f01caff545) +--- + src/network/networkd-routing-policy-rule.c | 19 +++++++++++-------- + 1 file changed, 11 insertions(+), 8 deletions(-) + +diff --git a/src/network/networkd-routing-policy-rule.c b/src/network/networkd-routing-policy-rule.c +index 2dc7862..21a40fa 100644 +--- a/src/network/networkd-routing-policy-rule.c ++++ b/src/network/networkd-routing-policy-rule.c +@@ -1260,15 +1260,18 @@ void routing_policy_rule_purge(Manager *m, Link *link) { + + SET_FOREACH(rule, m->rules_saved, i) { + existing = set_get(m->rules_foreign, rule); +- if (existing) { ++ if (!existing) ++ continue; /* Saved rule does not exist anymore. */ + +- r = routing_policy_rule_remove(rule, link, NULL); +- if (r < 0) { +- log_warning_errno(r, "Could not remove routing policy rules: %m"); +- continue; +- } +- +- link->routing_policy_rule_remove_messages++; ++ r = routing_policy_rule_remove(existing, link, NULL); ++ if (r < 0) { ++ log_warning_errno(r, "Could not remove routing policy rules: %m"); ++ continue; + } ++ ++ link->routing_policy_rule_remove_messages++; ++ ++ assert_se(set_remove(m->rules_foreign, existing) == existing); ++ routing_policy_rule_free(existing); + } + } diff --git a/debian/patches/networkd-clarify-that-IPv6-RA-uses-our-own-stack-no-the-k.patch b/debian/patches/networkd-clarify-that-IPv6-RA-uses-our-own-stack-no-the-k.patch new file mode 100644 index 0000000..8b7b4d8 --- /dev/null +++ b/debian/patches/networkd-clarify-that-IPv6-RA-uses-our-own-stack-no-the-k.patch @@ -0,0 +1,26 @@ +From: Lennart Poettering <lennart@poettering.net> +Date: Wed, 13 Mar 2019 17:00:56 +0100 +Subject: networkd: clarify that IPv6 RA uses our own stack, no the kernel's + +Fixes: #8906 +(cherry picked from commit c4a05aa1a8338013108d099de805f3262a871c0f) +--- + man/systemd.network.xml | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/man/systemd.network.xml b/man/systemd.network.xml +index ee464ff..12be72a 100644 +--- a/man/systemd.network.xml ++++ b/man/systemd.network.xml +@@ -632,6 +632,11 @@ + url="https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt">ip-sysctl.txt</ulink> in the kernel + documentation regarding <literal>accept_ra</literal>, but note that systemd's setting of + <constant>1</constant> (i.e. true) corresponds to kernel's setting of <constant>2</constant>.</para> ++ ++ <para>Note that if this option is enabled a userspace implementation of the IPv6 RA protocol is ++ used, and the kernel's own implementation remains disabled, since `networkd` needs to know all ++ details supplied in the advertisements, and these are not available from the kernel if the kernel's ++ own implemenation is used.</para> + </listitem> + </varlistentry> + <varlistentry> diff --git a/debian/patches/networkd-do-not-generate-MAC-for-bridge-device.patch b/debian/patches/networkd-do-not-generate-MAC-for-bridge-device.patch new file mode 100644 index 0000000..b8788fb --- /dev/null +++ b/debian/patches/networkd-do-not-generate-MAC-for-bridge-device.patch @@ -0,0 +1,24 @@ +From: Susant Sahani <ssahani@gmail.com> +Date: Tue, 14 May 2019 11:45:23 +0200 +Subject: networkd: do not generate MAC for bridge device. + +closes https://github.com/systemd/systemd/issues/12558 + +(cherry picked from commit deb2cfa4c6885d448eb1f17e5ef1b139106b7e86) +--- + src/network/netdev/netdev.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/network/netdev/netdev.c b/src/network/netdev/netdev.c +index ecd6cf4..6ef1631 100644 +--- a/src/network/netdev/netdev.c ++++ b/src/network/netdev/netdev.c +@@ -720,7 +720,7 @@ int netdev_load_one(Manager *manager, const char *filename) { + if (!netdev->filename) + return log_oom(); + +- if (!netdev->mac && netdev->kind != NETDEV_KIND_VLAN) { ++ if (!netdev->mac && !IN_SET(netdev->kind, NETDEV_KIND_VLAN, NETDEV_KIND_BRIDGE)) { + r = netdev_get_mac(netdev->ifname, &netdev->mac); + if (r < 0) + return log_error_errno(r, "Failed to generate predictable MAC address for %s: %m", netdev->ifname); diff --git a/debian/patches/networkd-fix-link_up-12505.patch b/debian/patches/networkd-fix-link_up-12505.patch new file mode 100644 index 0000000..a801d61 --- /dev/null +++ b/debian/patches/networkd-fix-link_up-12505.patch @@ -0,0 +1,62 @@ +From: Susant Sahani <ssahani@gmail.com> +Date: Thu, 9 May 2019 07:35:35 +0530 +Subject: networkd: fix link_up() (#12505) + +Fillup IFLA_INET6_ADDR_GEN_MODE while we do link_up. + +Fixes the following error: +``` +dummy-test: Could not bring up interface: Invalid argument +``` + +After reading the kernel code when we do a link up +``` +net/core/rtnetlink.c +IFLA_AF_SPEC + af_ops->set_link_af(dev, af); + inet6_set_link_af + if (tb[IFLA_INET6_ADDR_GEN_MODE]) + Here it looks for IFLA_INET6_ADDR_GEN_MODE +``` +Since link up we didn't filling up that it's failing. + +Closes #12504. + +(cherry picked from commit 4eb086a38712ea98faf41e075b84555b11b54362) +--- + src/network/networkd-link.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c +index 3cfdf4a..6445b94 100644 +--- a/src/network/networkd-link.c ++++ b/src/network/networkd-link.c +@@ -1918,6 +1918,8 @@ static int link_up(Link *link) { + } + + if (link_ipv6_enabled(link)) { ++ uint8_t ipv6ll_mode; ++ + r = sd_netlink_message_open_container(req, IFLA_AF_SPEC); + if (r < 0) + return log_link_error_errno(link, r, "Could not open IFLA_AF_SPEC container: %m"); +@@ -1933,6 +1935,19 @@ static int link_up(Link *link) { + return log_link_error_errno(link, r, "Could not append IFLA_INET6_TOKEN: %m"); + } + ++ if (!link_ipv6ll_enabled(link)) ++ ipv6ll_mode = IN6_ADDR_GEN_MODE_NONE; ++ else if (sysctl_read_ip_property(AF_INET6, link->ifname, "stable_secret", NULL) < 0) ++ /* The file may not exist. And event if it exists, when stable_secret is unset, ++ * reading the file fails with EIO. */ ++ ipv6ll_mode = IN6_ADDR_GEN_MODE_EUI64; ++ else ++ ipv6ll_mode = IN6_ADDR_GEN_MODE_STABLE_PRIVACY; ++ ++ r = sd_netlink_message_append_u8(req, IFLA_INET6_ADDR_GEN_MODE, ipv6ll_mode); ++ if (r < 0) ++ return log_link_error_errno(link, r, "Could not append IFLA_INET6_ADDR_GEN_MODE: %m"); ++ + r = sd_netlink_message_close_container(req); + if (r < 0) + return log_link_error_errno(link, r, "Could not close AF_INET6 container: %m"); diff --git a/debian/patches/networkd-test-disable-DNSSEC-in-domain-restricted-DNS-tes.patch b/debian/patches/networkd-test-disable-DNSSEC-in-domain-restricted-DNS-tes.patch new file mode 100644 index 0000000..8813a4a --- /dev/null +++ b/debian/patches/networkd-test-disable-DNSSEC-in-domain-restricted-DNS-tes.patch @@ -0,0 +1,33 @@ +From: Martin Pitt <martin@piware.de> +Date: Thu, 21 Feb 2019 12:24:16 +0100 +Subject: networkd-test: disable DNSSEC in domain-restricted DNS test + +dnsmasq 2.80 changed behaviour when being queried by resolved with +enabled DNSSEC: It returns errors for SOA and DS queries which cause the +entire query to fail. As we don't configure DNSSEC in this test anyway, +just disable it so that we retain compatibility with old and new dnsmasq +versions. + +(cherry picked from commit 6592c9c850675fb20236271efc4f65acbe3bfa00) +--- + test/networkd-test.py | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/test/networkd-test.py b/test/networkd-test.py +index 7011abc..71ee06f 100755 +--- a/test/networkd-test.py ++++ b/test/networkd-test.py +@@ -575,6 +575,13 @@ class DnsmasqClientTest(ClientTestBase, unittest.TestCase): + def test_resolved_domain_restricted_dns(self): + '''resolved: domain-restricted DNS servers''' + ++ # FIXME: resolvectl query fails with enabled DNSSEC against our dnsmasq ++ conf = '/run/systemd/resolved.conf.d/test-disable-dnssec.conf' ++ os.makedirs(os.path.dirname(conf), exist_ok=True) ++ with open(conf, 'w') as f: ++ f.write('[Resolve]\nDNSSEC=no\n') ++ self.addCleanup(os.remove, conf) ++ + # create interface for generic connections; this will map all DNS names + # to 192.168.42.1 + self.create_iface(dnsmasq_opts=['--address=/#/192.168.42.1']) diff --git a/debian/patches/networkd-test-fix-test_dropin.patch b/debian/patches/networkd-test-fix-test_dropin.patch new file mode 100644 index 0000000..1e17745 --- /dev/null +++ b/debian/patches/networkd-test-fix-test_dropin.patch @@ -0,0 +1,34 @@ +From: Martin Pitt <martin@piware.de> +Date: Thu, 21 Feb 2019 12:34:23 +0100 +Subject: networkd-test: fix test_dropin() + + - This test needs resolved, so make sure it is started. In some Debian + environments it is not. + - It was an unnecessary, and now failing assumption that name servers + get atomically written to the resolved's resolv.conf. Wait until both + expected name servers are in the file. + +(cherry picked from commit f5cf985e9cc6fff747ca17acadb1b4751076103b) +--- + test/networkd-test.py | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/test/networkd-test.py b/test/networkd-test.py +index c03e760..9487910 100755 +--- a/test/networkd-test.py ++++ b/test/networkd-test.py +@@ -950,12 +950,12 @@ DNS=192.168.42.1''') + [Network] + DNS=127.0.0.1''') + +- subprocess.check_call(['systemctl', 'start', 'systemd-networkd']) ++ subprocess.check_call(['systemctl', 'start', 'systemd-resolved', 'systemd-networkd']) + + for timeout in range(50): + with open(RESOLV_CONF) as f: + contents = f.read() +- if ' 127.0.0.1' in contents: ++ if ' 127.0.0.1' in contents and '192.168.42.1' in contents: + break + time.sleep(0.1) + self.assertIn('nameserver 192.168.42.1\n', contents) diff --git a/debian/patches/networkd-test-ignore-failures-of-test_route_only_dns-in-c.patch b/debian/patches/networkd-test-ignore-failures-of-test_route_only_dns-in-c.patch new file mode 100644 index 0000000..72e5042 --- /dev/null +++ b/debian/patches/networkd-test-ignore-failures-of-test_route_only_dns-in-c.patch @@ -0,0 +1,61 @@ +From: Martin Pitt <martin@piware.de> +Date: Wed, 27 Feb 2019 23:15:31 +0100 +Subject: networkd-test: ignore failures of test_route_only_dns* in containers + +This test exposes a race condition when running in LXC, see issue #11848 +for details. Until that is understood and fixed, skip the test as it's +not a recent regression. + +(cherry picked from commit 09b8826ea371e027c76a573a226bfd8f8c5652a2) +--- + test/networkd-test.py | 23 +++++++++++++++++++---- + 1 file changed, 19 insertions(+), 4 deletions(-) + +diff --git a/test/networkd-test.py b/test/networkd-test.py +index 9487910..6efeef9 100755 +--- a/test/networkd-test.py ++++ b/test/networkd-test.py +@@ -29,6 +29,7 @@ import time + import unittest + + HAVE_DNSMASQ = shutil.which('dnsmasq') is not None ++IS_CONTAINER = subprocess.call(['systemd-detect-virt', '--quiet', '--container']) == 0 + + NETWORK_UNITDIR = '/run/systemd/network' + +@@ -476,8 +477,15 @@ Address=192.168.42.100 + DNS=192.168.42.1 + Domains= ~company''') + +- self.do_test(coldplug=True, ipv6=False, +- extra_opts='IPv6AcceptRouterAdvertisements=False') ++ try: ++ self.do_test(coldplug=True, ipv6=False, ++ extra_opts='IPv6AcceptRouterAdvertisements=False') ++ except subprocess.CalledProcessError as e: ++ # networkd often fails to start in LXC: https://github.com/systemd/systemd/issues/11848 ++ if IS_CONTAINER and e.cmd == ['systemctl', 'start', 'systemd-networkd']: ++ raise unittest.SkipTest('https://github.com/systemd/systemd/issues/11848') ++ else: ++ raise + + with open(RESOLV_CONF) as f: + contents = f.read() +@@ -500,8 +508,15 @@ Address=192.168.42.100 + DNS=192.168.42.1 + Domains= ~company ~.''') + +- self.do_test(coldplug=True, ipv6=False, +- extra_opts='IPv6AcceptRouterAdvertisements=False') ++ try: ++ self.do_test(coldplug=True, ipv6=False, ++ extra_opts='IPv6AcceptRouterAdvertisements=False') ++ except subprocess.CalledProcessError as e: ++ # networkd often fails to start in LXC: https://github.com/systemd/systemd/issues/11848 ++ if IS_CONTAINER and e.cmd == ['systemctl', 'start', 'systemd-networkd']: ++ raise unittest.SkipTest('https://github.com/systemd/systemd/issues/11848') ++ else: ++ raise + + with open(RESOLV_CONF) as f: + contents = f.read() diff --git a/debian/patches/networkd-test-use-a-complete-domain-name-in-test_route_on.patch b/debian/patches/networkd-test-use-a-complete-domain-name-in-test_route_on.patch new file mode 100644 index 0000000..a37980b --- /dev/null +++ b/debian/patches/networkd-test-use-a-complete-domain-name-in-test_route_on.patch @@ -0,0 +1,87 @@ +From: Martin Pitt <martin@piware.de> +Date: Thu, 21 Feb 2019 12:26:44 +0100 +Subject: networkd-test: use a complete domain name in test_route_only_dns() + +Since version 241 (commit ea4678?), querying MX type records for +single-label domains does not actually forward the query to the DNS +server any more. Use "example.com" instead, which is the recommended +test domain anyway. + +(cherry picked from commit ca56805c8de43fc21ab4657cf5ebd1e0248527ac) +--- + test/networkd-test.py | 32 ++++++++++++++++---------------- + 1 file changed, 16 insertions(+), 16 deletions(-) + +diff --git a/test/networkd-test.py b/test/networkd-test.py +index 71ee06f..c03e760 100755 +--- a/test/networkd-test.py ++++ b/test/networkd-test.py +@@ -655,52 +655,52 @@ Domains= ~company ~lab''') + '''resolved queries to /etc/hosts''' + + # FIXME: -t MX query fails with enabled DNSSEC (even when using +- # the known negative trust anchor .internal instead of .example) ++ # the known negative trust anchor .internal instead of .example.com) + conf = '/run/systemd/resolved.conf.d/test-disable-dnssec.conf' + os.makedirs(os.path.dirname(conf), exist_ok=True) + with open(conf, 'w') as f: + f.write('[Resolve]\nDNSSEC=no\nLLMNR=no\nMulticastDNS=no\n') + self.addCleanup(os.remove, conf) + +- # create /etc/hosts bind mount which resolves my.example for IPv4 ++ # create /etc/hosts bind mount which resolves my.example.com for IPv4 + hosts = os.path.join(self.workdir, 'hosts') + with open(hosts, 'w') as f: +- f.write('172.16.99.99 my.example\n') ++ f.write('172.16.99.99 my.example.com\n') + subprocess.check_call(['mount', '--bind', hosts, '/etc/hosts']) + self.addCleanup(subprocess.call, ['umount', '/etc/hosts']) + subprocess.check_call(['systemctl', 'stop', 'systemd-resolved.service']) + + # note: different IPv4 address here, so that it's easy to tell apart + # what resolved the query +- self.create_iface(dnsmasq_opts=['--host-record=my.example,172.16.99.1,2600::99:99', +- '--host-record=other.example,172.16.0.42,2600::42', +- '--mx-host=example,mail.example'], ++ self.create_iface(dnsmasq_opts=['--host-record=my.example.com,172.16.99.1,2600::99:99', ++ '--host-record=other.example.com,172.16.0.42,2600::42', ++ '--mx-host=example.com,mail.example.com'], + ipv6=True) + self.do_test(coldplug=None, ipv6=True) + + try: + # family specific queries +- out = subprocess.check_output(['resolvectl', 'query', '-4', 'my.example']) +- self.assertIn(b'my.example: 172.16.99.99', out) ++ out = subprocess.check_output(['resolvectl', 'query', '-4', 'my.example.com']) ++ self.assertIn(b'my.example.com: 172.16.99.99', out) + # we don't expect an IPv6 answer; if /etc/hosts has any IP address, + # it's considered a sufficient source +- self.assertNotEqual(subprocess.call(['resolvectl', 'query', '-6', 'my.example']), 0) ++ self.assertNotEqual(subprocess.call(['resolvectl', 'query', '-6', 'my.example.com']), 0) + # "any family" query; IPv4 should come from /etc/hosts +- out = subprocess.check_output(['resolvectl', 'query', 'my.example']) +- self.assertIn(b'my.example: 172.16.99.99', out) ++ out = subprocess.check_output(['resolvectl', 'query', 'my.example.com']) ++ self.assertIn(b'my.example.com: 172.16.99.99', out) + # IP → name lookup; again, takes the /etc/hosts one + out = subprocess.check_output(['resolvectl', 'query', '172.16.99.99']) +- self.assertIn(b'172.16.99.99: my.example', out) ++ self.assertIn(b'172.16.99.99: my.example.com', out) + + # non-address RRs should fall back to DNS +- out = subprocess.check_output(['resolvectl', 'query', '--type=MX', 'example']) +- self.assertIn(b'example IN MX 1 mail.example', out) ++ out = subprocess.check_output(['resolvectl', 'query', '--type=MX', 'example.com']) ++ self.assertIn(b'example.com IN MX 1 mail.example.com', out) + + # other domains query DNS +- out = subprocess.check_output(['resolvectl', 'query', 'other.example']) ++ out = subprocess.check_output(['resolvectl', 'query', 'other.example.com']) + self.assertIn(b'172.16.0.42', out) + out = subprocess.check_output(['resolvectl', 'query', '172.16.0.42']) +- self.assertIn(b'172.16.0.42: other.example', out) ++ self.assertIn(b'172.16.0.42: other.example.com', out) + except (AssertionError, subprocess.CalledProcessError): + self.show_journal('systemd-resolved.service') + self.print_server_log() diff --git a/debian/patches/pam-systemd-use-secure_getenv-rather-than-getenv.patch b/debian/patches/pam-systemd-use-secure_getenv-rather-than-getenv.patch new file mode 100644 index 0000000..b966fe3 --- /dev/null +++ b/debian/patches/pam-systemd-use-secure_getenv-rather-than-getenv.patch @@ -0,0 +1,40 @@ +From: Lennart Poettering <lennart@poettering.net> +Date: Mon, 4 Feb 2019 10:23:43 +0100 +Subject: pam-systemd: use secure_getenv() rather than getenv() + +And explain why in a comment. + +(cherry picked from commit 83d4ab55336ff8a0643c6aa627b31e351a24040a) +--- + src/login/pam_systemd.c | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/src/login/pam_systemd.c b/src/login/pam_systemd.c +index 997b74e..ea245c8 100644 +--- a/src/login/pam_systemd.c ++++ b/src/login/pam_systemd.c +@@ -316,14 +316,21 @@ static const char* getenv_harder(pam_handle_t *handle, const char *key, const ch + assert(handle); + assert(key); + +- /* Looks for an environment variable, preferrably in the environment block associated with the specified PAM +- * handle, falling back to the process' block instead. */ ++ /* Looks for an environment variable, preferrably in the environment block associated with the ++ * specified PAM handle, falling back to the process' block instead. Why check both? Because we want ++ * to permit configuration of session properties from unit files that invoke PAM services, so that ++ * PAM services don't have to be reworked to set systemd-specific properties, but these properties ++ * can still be set from the unit file Environment= block. */ + + v = pam_getenv(handle, key); + if (!isempty(v)) + return v; + +- v = getenv(key); ++ /* We use secure_getenv() here, since we might get loaded into su/sudo, which are SUID. Ideally ++ * they'd clean up the environment before invoking foreign code (such as PAM modules), but alas they ++ * currently don't (to be precise, they clean up the environment they pass to their children, but ++ * not their own environ[]). */ ++ v = secure_getenv(key); + if (!isempty(v)) + return v; + diff --git a/debian/patches/polkit-on-async-pk-requests-re-validate-action-details.patch b/debian/patches/polkit-on-async-pk-requests-re-validate-action-details.patch new file mode 100644 index 0000000..c6ffacf --- /dev/null +++ b/debian/patches/polkit-on-async-pk-requests-re-validate-action-details.patch @@ -0,0 +1,81 @@ +From: Lennart Poettering <lennart@poettering.net> +Date: Wed, 22 Jan 2020 16:52:10 +0100 +Subject: polkit: on async pk requests, re-validate action/details + +When we do an async pk request, let's store which action/details we used +for the original request, and when we are called for the second time, +let's compare. If the action/details changed, let's not allow the access +to go through. + +(cherry picked from commit 7f56982289275ce84e20f0554475864953e6aaab) +(cherry picked from commit 0697d0d972c8d91395eb539a8e87e4aec8b37b75) +(cherry picked from commit 54791aff01aa93a8b621808d80ab506b54f245c8) +(cherry picked from commit 70d0f5ea5952a0cedd84c352070613df4ba5fc8f) +--- + src/shared/bus-polkit.c | 30 +++++++++++++++++++++++++++--- + 1 file changed, 27 insertions(+), 3 deletions(-) + +diff --git a/src/shared/bus-polkit.c b/src/shared/bus-polkit.c +index 81193b8..6343dd6 100644 +--- a/src/shared/bus-polkit.c ++++ b/src/shared/bus-polkit.c +@@ -155,6 +155,9 @@ int bus_test_polkit( + #if ENABLE_POLKIT + + typedef struct AsyncPolkitQuery { ++ char *action; ++ char **details; ++ + sd_bus_message *request, *reply; + sd_bus_message_handler_t callback; + void *userdata; +@@ -175,6 +178,9 @@ static void async_polkit_query_free(AsyncPolkitQuery *q) { + sd_bus_message_unref(q->request); + sd_bus_message_unref(q->reply); + ++ free(q->action); ++ strv_free(q->details); ++ + free(q); + } + +@@ -239,11 +245,17 @@ int bus_verify_polkit_async( + if (q) { + int authorized, challenge; + +- /* This is the second invocation of this function, and +- * there's already a response from polkit, let's +- * process it */ ++ /* This is the second invocation of this function, and there's already a response from ++ * polkit, let's process it */ + assert(q->reply); + ++ /* If the operation we want to authenticate changed between the first and the second time, ++ * let's not use this authentication, it might be out of date as the object and context we ++ * operate on might have changed. */ ++ if (!streq(q->action, action) || ++ !strv_equal(q->details, (char**) details)) ++ return -ESTALE; ++ + if (sd_bus_message_is_method_error(q->reply, NULL)) { + const sd_bus_error *e; + +@@ -339,6 +351,18 @@ int bus_verify_polkit_async( + q->callback = callback; + q->userdata = userdata; + ++ q->action = strdup(action); ++ if (!q->action) { ++ async_polkit_query_free(q); ++ return -ENOMEM; ++ } ++ ++ q->details = strv_copy((char**) details); ++ if (!q->details) { ++ async_polkit_query_free(q); ++ return -ENOMEM; ++ } ++ + r = hashmap_put(*registry, call, q); + if (r < 0) { + async_polkit_query_free(q); diff --git a/debian/patches/polkit-reuse-some-common-bus-message-appending-code.patch b/debian/patches/polkit-reuse-some-common-bus-message-appending-code.patch new file mode 100644 index 0000000..98e43ca --- /dev/null +++ b/debian/patches/polkit-reuse-some-common-bus-message-appending-code.patch @@ -0,0 +1,107 @@ +From: Lennart Poettering <lennart@poettering.net> +Date: Wed, 22 Jan 2020 16:44:43 +0100 +Subject: polkit: reuse some common bus message appending code + +(cherry picked from commit 95f82ae9d774f3508ce89dcbdd0714ef7385df59) +(cherry picked from commit 2589995acdb297a073270b54d8fff54b98fa57e9) +(cherry picked from commit 81532beddcc3b7946a573e15641742c452c66db7) +(cherry picked from commit 18b7b7fe307f03928bfea3ef0663048b7be6e4fb) +--- + src/shared/bus-polkit.c | 56 ++++++++++++++++++++++++++++--------------------- + 1 file changed, 32 insertions(+), 24 deletions(-) + +diff --git a/src/shared/bus-polkit.c b/src/shared/bus-polkit.c +index f93aa17..81193b8 100644 +--- a/src/shared/bus-polkit.c ++++ b/src/shared/bus-polkit.c +@@ -30,6 +30,34 @@ static int check_good_user(sd_bus_message *m, uid_t good_user) { + return sender_uid == good_user; + } + ++#if ENABLE_POLKIT ++static int bus_message_append_strv_key_value( ++ sd_bus_message *m, ++ const char **l) { ++ ++ const char **k, **v; ++ int r; ++ ++ assert(m); ++ ++ r = sd_bus_message_open_container(m, 'a', "{ss}"); ++ if (r < 0) ++ return r; ++ ++ STRV_FOREACH_PAIR(k, v, l) { ++ r = sd_bus_message_append(m, "{ss}", *k, *v); ++ if (r < 0) ++ return r; ++ } ++ ++ r = sd_bus_message_close_container(m); ++ if (r < 0) ++ return r; ++ ++ return r; ++} ++#endif ++ + int bus_test_polkit( + sd_bus_message *call, + int capability, +@@ -60,7 +88,7 @@ int bus_test_polkit( + _cleanup_(sd_bus_message_unrefp) sd_bus_message *request = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + int authorized = false, challenge = false; +- const char *sender, **k, **v; ++ const char *sender; + + sender = sd_bus_message_get_sender(call); + if (!sender) +@@ -84,17 +112,7 @@ int bus_test_polkit( + if (r < 0) + return r; + +- r = sd_bus_message_open_container(request, 'a', "{ss}"); +- if (r < 0) +- return r; +- +- STRV_FOREACH_PAIR(k, v, details) { +- r = sd_bus_message_append(request, "{ss}", *k, *v); +- if (r < 0) +- return r; +- } +- +- r = sd_bus_message_close_container(request); ++ r = bus_message_append_strv_key_value(request, details); + if (r < 0) + return r; + +@@ -201,7 +219,7 @@ int bus_verify_polkit_async( + #if ENABLE_POLKIT + _cleanup_(sd_bus_message_unrefp) sd_bus_message *pk = NULL; + AsyncPolkitQuery *q; +- const char *sender, **k, **v; ++ const char *sender; + sd_bus_message_handler_t callback; + void *userdata; + int c; +@@ -305,17 +323,7 @@ int bus_verify_polkit_async( + if (r < 0) + return r; + +- r = sd_bus_message_open_container(pk, 'a', "{ss}"); +- if (r < 0) +- return r; +- +- STRV_FOREACH_PAIR(k, v, details) { +- r = sd_bus_message_append(pk, "{ss}", *k, *v); +- if (r < 0) +- return r; +- } +- +- r = sd_bus_message_close_container(pk); ++ r = bus_message_append_strv_key_value(pk, details); + if (r < 0) + return r; + diff --git a/debian/patches/polkit-use-structured-initialization.patch b/debian/patches/polkit-use-structured-initialization.patch new file mode 100644 index 0000000..683fb3b --- /dev/null +++ b/debian/patches/polkit-use-structured-initialization.patch @@ -0,0 +1,36 @@ +From: Lennart Poettering <lennart@poettering.net> +Date: Wed, 22 Jan 2020 16:53:59 +0100 +Subject: polkit: use structured initialization + +(cherry picked from commit f4425c72c7395ec93ae00052916a66e2f60f200b) +(cherry picked from commit 5926f9f1723fd753a0c524ed96a13538c851395e) +(cherry picked from commit 4d80c8f158333117dabb0e6f7592059cddb1d6d0) +(cherry picked from commit 9131bb3d45e6384309eea42affd1aa757ef28cd7) +--- + src/shared/bus-polkit.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/src/shared/bus-polkit.c b/src/shared/bus-polkit.c +index 6343dd6..c42c39a 100644 +--- a/src/shared/bus-polkit.c ++++ b/src/shared/bus-polkit.c +@@ -343,13 +343,15 @@ int bus_verify_polkit_async( + if (r < 0) + return r; + +- q = new0(AsyncPolkitQuery, 1); ++ q = new(AsyncPolkitQuery, 1); + if (!q) + return -ENOMEM; + +- q->request = sd_bus_message_ref(call); +- q->callback = callback; +- q->userdata = userdata; ++ *q = (AsyncPolkitQuery) { ++ .request = sd_bus_message_ref(call), ++ .callback = callback, ++ .userdata = userdata, ++ }; + + q->action = strdup(action); + if (!q->action) { diff --git a/debian/patches/polkit-when-authorizing-via-PK-let-s-re-resolve-callback-.patch b/debian/patches/polkit-when-authorizing-via-PK-let-s-re-resolve-callback-.patch new file mode 100644 index 0000000..2175b78 --- /dev/null +++ b/debian/patches/polkit-when-authorizing-via-PK-let-s-re-resolve-callback-.patch @@ -0,0 +1,166 @@ +From: Lennart Poettering <lennart@poettering.net> +Date: Wed, 22 Jan 2020 17:07:47 +0100 +Subject: polkit: when authorizing via PK let's re-resolve callback/userdata + instead of caching it + +Previously, when doing an async PK query we'd store the original +callback/userdata pair and call it again after the PK request is +complete. This is problematic, since PK queries might be slow and in the +meantime the userdata might be released and re-acquired. Let's avoid +this by always traversing through the message handlers so that we always +re-resolve the callback and userdata pair and thus can be sure it's +up-to-date and properly valid. + +(cherry picked from commit 637486261528e8aa3da9f26a4487dc254f4b7abb) +(cherry picked from commit e2d4cb9843c50eff76e9104fec6b448c0d7c8814) +(cherry picked from commit fb21e13e8ecbe25d80c1219b14e6495795df18ef) +(cherry picked from commit c3141774dfb84b1526c4991bb775457c739eb179) +--- + src/shared/bus-polkit.c | 78 ++++++++++++++++++++++++++++++++----------------- + 1 file changed, 52 insertions(+), 26 deletions(-) + +diff --git a/src/shared/bus-polkit.c b/src/shared/bus-polkit.c +index c42c39a..02c11aa 100644 +--- a/src/shared/bus-polkit.c ++++ b/src/shared/bus-polkit.c +@@ -159,14 +159,13 @@ typedef struct AsyncPolkitQuery { + char **details; + + sd_bus_message *request, *reply; +- sd_bus_message_handler_t callback; +- void *userdata; + sd_bus_slot *slot; ++ + Hashmap *registry; ++ sd_event_source *defer_event_source; + } AsyncPolkitQuery; + + static void async_polkit_query_free(AsyncPolkitQuery *q) { +- + if (!q) + return; + +@@ -181,9 +180,24 @@ static void async_polkit_query_free(AsyncPolkitQuery *q) { + free(q->action); + strv_free(q->details); + ++ if (q->defer_event_source) ++ (void) sd_event_source_set_enabled(q->defer_event_source, SD_EVENT_OFF); ++ sd_event_source_unref(q->defer_event_source); + free(q); + } + ++static int async_polkit_defer(sd_event_source *s, void *userdata) { ++ AsyncPolkitQuery *q = userdata; ++ ++ assert(s); ++ ++ /* This is called as idle event source after we processed the async polkit reply, hopefully after the ++ * method call we re-enqueued has been properly processed. */ ++ ++ async_polkit_query_free(q); ++ return 0; ++} ++ + static int async_polkit_callback(sd_bus_message *reply, void *userdata, sd_bus_error *error) { + _cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL; + AsyncPolkitQuery *q = userdata; +@@ -192,21 +206,46 @@ static int async_polkit_callback(sd_bus_message *reply, void *userdata, sd_bus_e + assert(reply); + assert(q); + ++ assert(q->slot); + q->slot = sd_bus_slot_unref(q->slot); ++ ++ assert(!q->reply); + q->reply = sd_bus_message_ref(reply); + ++ /* Now, let's dispatch the original message a second time be re-enqueing. This will then traverse the ++ * whole message processing again, and thus re-validating and re-retrieving the "userdata" field ++ * again. ++ * ++ * We install an idle event loop event to clean-up the PolicyKit request data when we are idle again, ++ * i.e. after the second time the message is processed is complete. */ ++ ++ assert(!q->defer_event_source); ++ r = sd_event_add_defer(sd_bus_get_event(sd_bus_message_get_bus(reply)), &q->defer_event_source, async_polkit_defer, q); ++ if (r < 0) ++ goto fail; ++ ++ r = sd_event_source_set_priority(q->defer_event_source, SD_EVENT_PRIORITY_IDLE); ++ if (r < 0) ++ goto fail; ++ ++ r = sd_event_source_set_enabled(q->defer_event_source, SD_EVENT_ONESHOT); ++ if (r < 0) ++ goto fail; ++ + r = sd_bus_message_rewind(q->request, true); +- if (r < 0) { +- r = sd_bus_reply_method_errno(q->request, r, NULL); +- goto finish; +- } ++ if (r < 0) ++ goto fail; ++ ++ r = sd_bus_enqeue_for_read(sd_bus_message_get_bus(q->request), q->request); ++ if (r < 0) ++ goto fail; + +- r = q->callback(q->request, q->userdata, &error_buffer); +- r = bus_maybe_reply_error(q->request, r, &error_buffer); ++ return 1; + +-finish: ++fail: ++ log_debug_errno(r, "Processing asynchronous PolicyKit reply failed, ignoring: %m"); ++ (void) sd_bus_reply_method_errno(q->request, r, NULL); + async_polkit_query_free(q); +- + return r; + } + +@@ -225,11 +264,9 @@ int bus_verify_polkit_async( + #if ENABLE_POLKIT + _cleanup_(sd_bus_message_unrefp) sd_bus_message *pk = NULL; + AsyncPolkitQuery *q; +- const char *sender; +- sd_bus_message_handler_t callback; +- void *userdata; + int c; + #endif ++ const char *sender; + int r; + + assert(call); +@@ -293,20 +330,11 @@ int bus_verify_polkit_async( + else if (r > 0) + return 1; + +-#if ENABLE_POLKIT +- if (sd_bus_get_current_message(call->bus) != call) +- return -EINVAL; +- +- callback = sd_bus_get_current_handler(call->bus); +- if (!callback) +- return -EINVAL; +- +- userdata = sd_bus_get_current_userdata(call->bus); +- + sender = sd_bus_message_get_sender(call); + if (!sender) + return -EBADMSG; + ++#if ENABLE_POLKIT + c = sd_bus_message_get_allow_interactive_authorization(call); + if (c < 0) + return c; +@@ -349,8 +377,6 @@ int bus_verify_polkit_async( + + *q = (AsyncPolkitQuery) { + .request = sd_bus_message_ref(call), +- .callback = callback, +- .userdata = userdata, + }; + + q->action = strdup(action); diff --git a/debian/patches/random-util-eat-up-bad-RDRAND-values-seen-on-AMD-CPUs.patch b/debian/patches/random-util-eat-up-bad-RDRAND-values-seen-on-AMD-CPUs.patch new file mode 100644 index 0000000..5c464ad --- /dev/null +++ b/debian/patches/random-util-eat-up-bad-RDRAND-values-seen-on-AMD-CPUs.patch @@ -0,0 +1,54 @@ +From: Michael Biebl <biebl@debian.org> +Date: Tue, 14 May 2019 13:12:35 +0200 +Subject: random-util: eat up bad RDRAND values seen on AMD CPUs + +An ugly, ugly work-around for #11810. And no, we shouldn't have to do +this. This is something for AMD, the firmware or the kernel to +fix/work-around, not us. But nonetheless, this should do it for now. + +Fixes: #11810 +(cherry picked from commit 1c53d4a070edbec8ad2d384ba0014d0eb6bae077) +--- + src/basic/random-util.c | 15 ++++++++++++++- + 1 file changed, 14 insertions(+), 1 deletion(-) + +diff --git a/src/basic/random-util.c b/src/basic/random-util.c +index f7decf6..38f8180 100644 +--- a/src/basic/random-util.c ++++ b/src/basic/random-util.c +@@ -37,6 +37,7 @@ int rdrand(unsigned long *ret) { + + #if defined(__i386__) || defined(__x86_64__) + static int have_rdrand = -1; ++ unsigned long v; + unsigned char err; + + if (have_rdrand < 0) { +@@ -56,7 +57,7 @@ int rdrand(unsigned long *ret) { + + asm volatile("rdrand %0;" + "setc %1" +- : "=r" (*ret), ++ : "=r" (v), + "=qm" (err)); + + #if HAS_FEATURE_MEMORY_SANITIZER +@@ -66,6 +67,18 @@ int rdrand(unsigned long *ret) { + if (!err) + return -EAGAIN; + ++ /* Apparently on some AMD CPUs RDRAND will sometimes (after a suspend/resume cycle?) report success ++ * via the carry flag but nonetheless return the same fixed value -1 in all cases. This appears to be ++ * a bad bug in the CPU or firmware. Let's deal with that and work-around this by explicitly checking ++ * for this special value (and also 0, just to be sure) and filtering it out. This is a work-around ++ * only however and something AMD really should fix properly. The Linux kernel should probably work ++ * around this issue by turning off RDRAND altogether on those CPUs. See: ++ * https://github.com/systemd/systemd/issues/11810 */ ++ if (v == 0 || v == ULONG_MAX) ++ return log_debug_errno(SYNTHETIC_ERRNO(EUCLEAN), ++ "RDRAND returned suspicious value %lx, assuming bad hardware RNG, not using value.", v); ++ ++ *ret = v; + return 0; + #else + return -EOPNOTSUPP; diff --git a/debian/patches/remove-.-path-components-from-required-mount-paths.patch b/debian/patches/remove-.-path-components-from-required-mount-paths.patch new file mode 100644 index 0000000..3cb5b6a --- /dev/null +++ b/debian/patches/remove-.-path-components-from-required-mount-paths.patch @@ -0,0 +1,30 @@ +From: Stephane Chazelas <stephane.chazelas@gmail.com> +Date: Wed, 6 Mar 2019 22:16:55 +0000 +Subject: remove "." path components from required mount paths + +unit_require_mounts_for may be passed path arguments that contain "." +components like for user's home directories where "." is sometimes used +to specify some form of anchor point. + +This change stops considering such path as an error and removes the "." +components instead. + +Closes: #11910 +(cherry picked from commit 106bf8e445a797f9d9c88b827ed42193f2f6b838) +--- + src/core/unit.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/core/unit.c b/src/core/unit.c +index 24b14fb..2a7359a 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -4607,7 +4607,7 @@ int unit_require_mounts_for(Unit *u, const char *path, UnitDependencyMask mask) + if (!p) + return -ENOMEM; + +- path = path_simplify(p, false); ++ path = path_simplify(p, true); + + if (!path_is_normalized(path)) + return -EPERM; diff --git a/debian/patches/resolve-fix-memleak.patch b/debian/patches/resolve-fix-memleak.patch new file mode 100644 index 0000000..f37f322 --- /dev/null +++ b/debian/patches/resolve-fix-memleak.patch @@ -0,0 +1,32 @@ +From: Yu Watanabe <watanabe.yu+github@gmail.com> +Date: Fri, 12 Jul 2019 14:19:36 +0900 +Subject: resolve: fix memleak + +(cherry picked from commit 2400ae29a55aab8659fa778f02d1884b86a95062) +(cherry picked from commit 7727e6c0ae1769ba7ea9959aa721236c025adbdf) +(cherry picked from commit 9755ac0744f858cfa952033552ac6f2401e0f2d0) +--- + src/resolve/resolved-manager.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c +index b3d35c8..2017b0e 100644 +--- a/src/resolve/resolved-manager.c ++++ b/src/resolve/resolved-manager.c +@@ -11,6 +11,7 @@ + + #include "af-list.h" + #include "alloc-util.h" ++#include "bus-util.h" + #include "dirent-util.h" + #include "dns-domain.h" + #include "fd-util.h" +@@ -689,6 +690,8 @@ Manager *manager_free(Manager *m) { + manager_mdns_stop(m); + manager_dns_stub_stop(m); + ++ bus_verify_polkit_async_registry_free(m->polkit_registry); ++ + sd_bus_flush_close_unref(m->bus); + + sd_event_source_unref(m->sigusr1_event_source); diff --git a/debian/patches/sd-bus-enforce-a-size-limit-on-D-Bus-object-paths.patch b/debian/patches/sd-bus-enforce-a-size-limit-on-D-Bus-object-paths.patch new file mode 100644 index 0000000..335fccc --- /dev/null +++ b/debian/patches/sd-bus-enforce-a-size-limit-on-D-Bus-object-paths.patch @@ -0,0 +1,215 @@ +From: Martin Pitt <martin@piware.de> +Date: Sun, 17 Feb 2019 10:17:45 +0100 +Subject: sd-bus: enforce a size limit on D-Bus object paths + +Replace stack with heap allocation. This avoids accessing/modifying +memory outside of the allocated stack region by sending specially +crafted D-Bus messages with very large object paths. + +Vulnerability discovered by Chris Coulson <chris.coulson@canonical.com>, +patch provided by Riccardo Schirone <rschiron@redhat.com>. + +CVE-2019-6454 +--- + src/libsystemd/sd-bus/bus-internal.c | 2 +- + src/libsystemd/sd-bus/bus-internal.h | 4 +++ + src/libsystemd/sd-bus/bus-objects.c | 64 ++++++++++++++++++++++++++++-------- + 3 files changed, 55 insertions(+), 15 deletions(-) + +diff --git a/src/libsystemd/sd-bus/bus-internal.c b/src/libsystemd/sd-bus/bus-internal.c +index 40acae2..598b7f1 100644 +--- a/src/libsystemd/sd-bus/bus-internal.c ++++ b/src/libsystemd/sd-bus/bus-internal.c +@@ -43,7 +43,7 @@ bool object_path_is_valid(const char *p) { + if (slash) + return false; + +- return true; ++ return (q - p) <= BUS_PATH_SIZE_MAX; + } + + char* object_path_startswith(const char *a, const char *b) { +diff --git a/src/libsystemd/sd-bus/bus-internal.h b/src/libsystemd/sd-bus/bus-internal.h +index f208b29..a8d61bf 100644 +--- a/src/libsystemd/sd-bus/bus-internal.h ++++ b/src/libsystemd/sd-bus/bus-internal.h +@@ -332,6 +332,10 @@ struct sd_bus { + + #define BUS_MESSAGE_SIZE_MAX (128*1024*1024) + #define BUS_AUTH_SIZE_MAX (64*1024) ++/* Note that the D-Bus specification states that bus paths shall have no size limit. We enforce here one ++ * anyway, since truly unbounded strings are a security problem. The limit we pick is relatively large however, ++ * to not clash unnecessarily with real-life applications. */ ++#define BUS_PATH_SIZE_MAX (64*1024) + + #define BUS_CONTAINER_DEPTH 128 + +diff --git a/src/libsystemd/sd-bus/bus-objects.c b/src/libsystemd/sd-bus/bus-objects.c +index 58329f3..983921d 100644 +--- a/src/libsystemd/sd-bus/bus-objects.c ++++ b/src/libsystemd/sd-bus/bus-objects.c +@@ -1133,7 +1133,8 @@ static int object_manager_serialize_path_and_fallbacks( + const char *path, + sd_bus_error *error) { + +- char *prefix; ++ _cleanup_free_ char *prefix = NULL; ++ size_t pl; + int r; + + assert(bus); +@@ -1149,7 +1150,11 @@ static int object_manager_serialize_path_and_fallbacks( + return 0; + + /* Second, add fallback vtables registered for any of the prefixes */ +- prefix = newa(char, strlen(path) + 1); ++ pl = strlen(path); ++ assert(pl <= BUS_PATH_SIZE_MAX); ++ prefix = new(char, pl + 1); ++ if (!prefix) ++ return -ENOMEM; + OBJECT_PATH_FOREACH_PREFIX(prefix, path) { + r = object_manager_serialize_path(bus, reply, prefix, path, true, error); + if (r < 0) +@@ -1345,6 +1350,7 @@ static int object_find_and_run( + } + + int bus_process_object(sd_bus *bus, sd_bus_message *m) { ++ _cleanup_free_ char *prefix = NULL; + int r; + size_t pl; + bool found_object = false; +@@ -1369,9 +1375,12 @@ int bus_process_object(sd_bus *bus, sd_bus_message *m) { + assert(m->member); + + pl = strlen(m->path); +- do { +- char prefix[pl+1]; ++ assert(pl <= BUS_PATH_SIZE_MAX); ++ prefix = new(char, pl + 1); ++ if (!prefix) ++ return -ENOMEM; + ++ do { + bus->nodes_modified = false; + + r = object_find_and_run(bus, m, m->path, false, &found_object); +@@ -1498,9 +1507,14 @@ static int bus_find_parent_object_manager(sd_bus *bus, struct node **out, const + + n = hashmap_get(bus->nodes, path); + if (!n) { +- char *prefix; ++ _cleanup_free_ char *prefix = NULL; ++ size_t pl; + +- prefix = newa(char, strlen(path) + 1); ++ pl = strlen(path); ++ assert(pl <= BUS_PATH_SIZE_MAX); ++ prefix = new(char, pl + 1); ++ if (!prefix) ++ return -ENOMEM; + OBJECT_PATH_FOREACH_PREFIX(prefix, path) { + n = hashmap_get(bus->nodes, prefix); + if (n) +@@ -2083,8 +2097,9 @@ _public_ int sd_bus_emit_properties_changed_strv( + const char *interface, + char **names) { + ++ _cleanup_free_ char *prefix = NULL; + bool found_interface = false; +- char *prefix; ++ size_t pl; + int r; + + assert_return(bus, -EINVAL); +@@ -2105,6 +2120,12 @@ _public_ int sd_bus_emit_properties_changed_strv( + + BUS_DONT_DESTROY(bus); + ++ pl = strlen(path); ++ assert(pl <= BUS_PATH_SIZE_MAX); ++ prefix = new(char, pl + 1); ++ if (!prefix) ++ return -ENOMEM; ++ + do { + bus->nodes_modified = false; + +@@ -2114,7 +2135,6 @@ _public_ int sd_bus_emit_properties_changed_strv( + if (bus->nodes_modified) + continue; + +- prefix = newa(char, strlen(path) + 1); + OBJECT_PATH_FOREACH_PREFIX(prefix, path) { + r = emit_properties_changed_on_interface(bus, prefix, path, interface, true, &found_interface, names); + if (r != 0) +@@ -2246,7 +2266,8 @@ static int object_added_append_all_prefix( + + static int object_added_append_all(sd_bus *bus, sd_bus_message *m, const char *path) { + _cleanup_set_free_ Set *s = NULL; +- char *prefix; ++ _cleanup_free_ char *prefix = NULL; ++ size_t pl; + int r; + + assert(bus); +@@ -2291,7 +2312,11 @@ static int object_added_append_all(sd_bus *bus, sd_bus_message *m, const char *p + if (bus->nodes_modified) + return 0; + +- prefix = newa(char, strlen(path) + 1); ++ pl = strlen(path); ++ assert(pl <= BUS_PATH_SIZE_MAX); ++ prefix = new(char, pl + 1); ++ if (!prefix) ++ return -ENOMEM; + OBJECT_PATH_FOREACH_PREFIX(prefix, path) { + r = object_added_append_all_prefix(bus, m, s, prefix, path, true); + if (r < 0) +@@ -2430,7 +2455,8 @@ static int object_removed_append_all_prefix( + + static int object_removed_append_all(sd_bus *bus, sd_bus_message *m, const char *path) { + _cleanup_set_free_ Set *s = NULL; +- char *prefix; ++ _cleanup_free_ char *prefix = NULL; ++ size_t pl; + int r; + + assert(bus); +@@ -2462,7 +2488,11 @@ static int object_removed_append_all(sd_bus *bus, sd_bus_message *m, const char + if (bus->nodes_modified) + return 0; + +- prefix = newa(char, strlen(path) + 1); ++ pl = strlen(path); ++ assert(pl <= BUS_PATH_SIZE_MAX); ++ prefix = new(char, pl + 1); ++ if (!prefix) ++ return -ENOMEM; + OBJECT_PATH_FOREACH_PREFIX(prefix, path) { + r = object_removed_append_all_prefix(bus, m, s, prefix, path, true); + if (r < 0) +@@ -2612,7 +2642,8 @@ static int interfaces_added_append_one( + const char *path, + const char *interface) { + +- char *prefix; ++ _cleanup_free_ char *prefix = NULL; ++ size_t pl; + int r; + + assert(bus); +@@ -2626,7 +2657,12 @@ static int interfaces_added_append_one( + if (bus->nodes_modified) + return 0; + +- prefix = newa(char, strlen(path) + 1); ++ pl = strlen(path); ++ assert(pl <= BUS_PATH_SIZE_MAX); ++ prefix = new(char, pl + 1); ++ if (!prefix) ++ return -ENOMEM; ++ + OBJECT_PATH_FOREACH_PREFIX(prefix, path) { + r = interfaces_added_append_one_prefix(bus, m, prefix, path, interface, true); + if (r != 0) diff --git a/debian/patches/sd-bus-introduce-API-for-re-enqueuing-incoming-messages.patch b/debian/patches/sd-bus-introduce-API-for-re-enqueuing-incoming-messages.patch new file mode 100644 index 0000000..b19d8fc --- /dev/null +++ b/debian/patches/sd-bus-introduce-API-for-re-enqueuing-incoming-messages.patch @@ -0,0 +1,65 @@ +From: Lennart Poettering <lennart@poettering.net> +Date: Wed, 22 Jan 2020 17:05:17 +0100 +Subject: sd-bus: introduce API for re-enqueuing incoming messages + +When authorizing via PolicyKit we want to process incoming method calls +twice: once to process and figure out that we need PK authentication, +and a second time after we acquired PK authentication to actually execute +the operation. With this new call sd_bus_enqueue_for_read() we have a +way to put an incoming message back into the read queue for this +purpose. + +This might have other uses too, for example debugging. + +(cherry picked from commit 1068447e6954dc6ce52f099ed174c442cb89ed54) + +zjs: patch modified to not make the function public +(cherry picked from commit 83bfc0d8dd026814d23e3fdfa46806394f775526) +(cherry picked from commit 2e504c92d195d407cec3ba9ed156b195c31a5f3f) +(cherry picked from commit 351627d4bfa39dd05f28d889967383af2372de6d) +--- + src/libsystemd/sd-bus/bus-message.h | 1 + + src/libsystemd/sd-bus/sd-bus.c | 24 ++++++++++++++++++++++++ + 2 files changed, 25 insertions(+) + +diff --git a/src/libsystemd/sd-bus/bus-message.h b/src/libsystemd/sd-bus/bus-message.h +index 0115437..7fd3f11 100644 +--- a/src/libsystemd/sd-bus/bus-message.h ++++ b/src/libsystemd/sd-bus/bus-message.h +@@ -211,3 +211,4 @@ int bus_message_remarshal(sd_bus *bus, sd_bus_message **m); + + void bus_message_set_sender_driver(sd_bus *bus, sd_bus_message *m); + void bus_message_set_sender_local(sd_bus *bus, sd_bus_message *m); ++int sd_bus_enqeue_for_read(sd_bus *bus, sd_bus_message *m); +diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c +index 1ff858f..94380af 100644 +--- a/src/libsystemd/sd-bus/sd-bus.c ++++ b/src/libsystemd/sd-bus/sd-bus.c +@@ -4144,3 +4144,27 @@ _public_ int sd_bus_get_close_on_exit(sd_bus *bus) { + + return bus->close_on_exit; + } ++ ++int sd_bus_enqeue_for_read(sd_bus *bus, sd_bus_message *m) { ++ int r; ++ ++ assert_return(bus, -EINVAL); ++ assert_return(bus = bus_resolve(bus), -ENOPKG); ++ assert_return(m, -EINVAL); ++ assert_return(m->sealed, -EINVAL); ++ assert_return(!bus_pid_changed(bus), -ECHILD); ++ ++ if (!BUS_IS_OPEN(bus->state)) ++ return -ENOTCONN; ++ ++ /* Re-enqeue a message for reading. This is primarily useful for PolicyKit-style authentication, ++ * where we want accept a message, then determine we need to interactively authenticate the user, and ++ * when we have that process the message again. */ ++ ++ r = bus_rqueue_make_room(bus); ++ if (r < 0) ++ return r; ++ ++ bus->rqueue[bus->rqueue_size++] = sd_bus_message_ref(m); ++ return 0; ++} diff --git a/debian/patches/sd-device-also-store-properties-read-from-udev-database-t.patch b/debian/patches/sd-device-also-store-properties-read-from-udev-database-t.patch new file mode 100644 index 0000000..1684698 --- /dev/null +++ b/debian/patches/sd-device-also-store-properties-read-from-udev-database-t.patch @@ -0,0 +1,51 @@ +From: Yu Watanabe <watanabe.yu+github@gmail.com> +Date: Sat, 16 Feb 2019 05:21:59 +0900 +Subject: sd-device: also store properties read from udev database to + sd_device::properties_db + +Follow-up for a3ce813697bcc1c4644e097a2f1cd0459326d6ee and +5ce41697bd3ddc19cd6e1e6834751082ca0c8b02. + +Before a3ce813697bcc1c4644e097a2f1cd0459326d6ee, all properties in +src->properties and src->properties_db are mixed and copied to +dst->properties_db by device_copy_properties(). +So, it is not necessary to store data from udev database file to +sd_device::properties_db before copying properties. + +But now, properties are not mixed. So, the read data need to be +stored to also ::properties_db. + +Fixes #11721. + +(cherry picked from commit 03dd7b7ddec1b0e06f254972a2e05f516a05edaf) +--- + src/libsystemd/sd-device/sd-device.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c +index 2a69f2e..9137a93 100644 +--- a/src/libsystemd/sd-device/sd-device.c ++++ b/src/libsystemd/sd-device/sd-device.c +@@ -1110,6 +1110,7 @@ int device_add_devlink(sd_device *device, const char *devlink) { + static int device_add_property_internal_from_string(sd_device *device, const char *str) { + _cleanup_free_ char *key = NULL; + char *value; ++ int r; + + assert(device); + assert(str); +@@ -1127,7 +1128,13 @@ static int device_add_property_internal_from_string(sd_device *device, const cha + if (isempty(++value)) + value = NULL; + +- return device_add_property_internal(device, key, value); ++ /* Add the property to both sd_device::properties and sd_device::properties_db, ++ * as this is called by only handle_db_line(). */ ++ r = device_add_property_aux(device, key, value, false); ++ if (r < 0) ++ return r; ++ ++ return device_add_property_aux(device, key, value, true); + } + + int device_set_usec_initialized(sd_device *device, usec_t when) { diff --git a/debian/patches/seccomp-allow-turning-off-of-seccomp-filtering-via-env-va.patch b/debian/patches/seccomp-allow-turning-off-of-seccomp-filtering-via-env-va.patch new file mode 100644 index 0000000..12d823f --- /dev/null +++ b/debian/patches/seccomp-allow-turning-off-of-seccomp-filtering-via-env-va.patch @@ -0,0 +1,79 @@ +From: Lennart Poettering <lennart@poettering.net> +Date: Mon, 2 Nov 2020 14:51:10 +0100 +Subject: seccomp: allow turning off of seccomp filtering via env var + +Fixes: #17504 + +Also suggested in: https://github.com/systemd/systemd/issues/17245#issuecomment-704773603 + +(cherry picked from commit ce8f6d478e3f6c6a313fb19615aa5029bb18f86d) +--- + docs/ENVIRONMENT.md | 3 +++ + src/nspawn/nspawn-seccomp.c | 2 +- + src/shared/seccomp-util.c | 19 +++++++++++++++---- + 3 files changed, 19 insertions(+), 5 deletions(-) + +diff --git a/docs/ENVIRONMENT.md b/docs/ENVIRONMENT.md +index 99b5b03..286a5e2 100644 +--- a/docs/ENVIRONMENT.md ++++ b/docs/ENVIRONMENT.md +@@ -58,6 +58,9 @@ All tools: + this only controls use of Unicode emoji glyphs, and has no effect on other + Unicode glyphs. + ++* `$SYSTEMD_SECCOMP=0` – if set, seccomp filters will not be enforced, even if ++ support for it is compiled in and available in the kernel. ++ + systemctl: + + * `$SYSTEMCTL_FORCE_BUS=1` — if set, do not connect to PID1's private D-Bus +diff --git a/src/nspawn/nspawn-seccomp.c b/src/nspawn/nspawn-seccomp.c +index e7ef80f..17abfce 100644 +--- a/src/nspawn/nspawn-seccomp.c ++++ b/src/nspawn/nspawn-seccomp.c +@@ -168,7 +168,7 @@ int setup_seccomp(uint64_t cap_list_retain, char **syscall_whitelist, char **sys + int r; + + if (!is_seccomp_available()) { +- log_debug("SECCOMP features not detected in the kernel, disabling SECCOMP filterering"); ++ log_debug("SECCOMP features not detected in the kernel or disabled at runtime, disabling SECCOMP filtering"); + return 0; + } + +diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c +index 958128c..cbab63c 100644 +--- a/src/shared/seccomp-util.c ++++ b/src/shared/seccomp-util.c +@@ -19,6 +19,7 @@ + #include "strv.h" + #include "util.h" + #include "errno-list.h" ++#include "env-util.h" + + const uint32_t seccomp_local_archs[] = { + +@@ -242,10 +243,20 @@ static bool is_seccomp_filter_available(void) { + bool is_seccomp_available(void) { + static int cached_enabled = -1; + +- if (cached_enabled < 0) +- cached_enabled = +- is_basic_seccomp_available() && +- is_seccomp_filter_available(); ++ if (cached_enabled < 0) { ++ int b; ++ ++ b = getenv_bool_secure("SYSTEMD_SECCOMP"); ++ if (b != 0) { ++ if (b < 0 && b != -ENXIO) /* ENXIO: env var unset */ ++ log_debug_errno(b, "Failed to parse $SYSTEMD_SECCOMP value, ignoring."); ++ ++ cached_enabled = ++ is_basic_seccomp_available() && ++ is_seccomp_filter_available(); ++ } else ++ cached_enabled = false; ++ } + + return cached_enabled; + } diff --git a/debian/patches/series b/debian/patches/series new file mode 100644 index 0000000..3952047 --- /dev/null +++ b/debian/patches/series @@ -0,0 +1,79 @@ +sd-bus-enforce-a-size-limit-on-D-Bus-object-paths.patch +udev-network-drop-unused-parent_driver-argument-from-net_.patch +sd-device-also-store-properties-read-from-udev-database-t.patch +networkd-test-disable-DNSSEC-in-domain-restricted-DNS-tes.patch +networkd-test-use-a-complete-domain-name-in-test_route_on.patch +networkd-test-fix-test_dropin.patch +networkd-test-ignore-failures-of-test_route_only_dns-in-c.patch +timedate-fix-emitted-value-when-ntp-client-is-enabled-dis.patch +cgtop-Fix-processing-of-controllers-other-than-CPU.patch +udev-restore-debug-level-when-logging-a-failure-in-the-ex.patch +remove-.-path-components-from-required-mount-paths.patch +Re-add-uaccess-tag-for-dev-dri-renderD.patch +udev-run-programs-in-the-specified-order.patch +bash-completion-use-default-completion-for-redirect-opera.patch +networkd-clarify-that-IPv6-RA-uses-our-own-stack-no-the-k.patch +network-remove-routing-policy-rule-from-foreign-rule-data.patch +network-do-not-remove-rule-when-it-is-requested-by-existi.patch +pam-systemd-use-secure_getenv-rather-than-getenv.patch +journal-remote-do-not-request-Content-Length-if-Transfer-.patch +systemctl-restore-systemctl-reboot-ARG-functionality.patch +random-util-eat-up-bad-RDRAND-values-seen-on-AMD-CPUs.patch +ask-password-prevent-buffer-overflow-when-reading-from-ke.patch +core-unset-HOME-that-the-kernel-gives-us.patch +man-add-note-that-h-u-U-are-mostly-useless.patch +sysctl-util-add-sysctl_read_ip_property.patch +network-check-whether-ipv6-is-enabled-in-sysctl.patch +network-ignore-requested-ipv6-addresses-when-ipv6-is-disa.patch +network-ignore-requested-ipv6-route-when-ipv6-is-disabled.patch +network-ignore-requested-ipv6-routing-policy-rule-when-ip.patch +network-read-link-specific-sysctl-value.patch +networkd-fix-link_up-12505.patch +network-do-not-send-ipv6-token-to-kernel.patch +meson-make-nologin-path-build-time-configurable.patch +core-never-propagate-reload-failure-to-service-result.patch +shared-seccomp-add-sync_file_range2.patch +core-factor-root_directory-application-out-of-apply_worki.patch +shared-bus-util-drop-trusted-annotation-from-bus_open_sys.patch +login-add-a-missing-error-check-for-session_set_leader.patch +namespace-make-MountFlags-shared-work-again.patch +mount-generators-do-not-make-unit-wanted-by-its-device-un.patch +mount-remove-unused-mount_is_auto-and-mount_is_automount.patch +core-set-fs.file-max-sysctl-to-LONG_MAX-rather-than-ULONG.patch +execute-remove-one-redundant-comparison-check.patch +core-change-ownership-mode-of-the-execution-directories-a.patch +bus-util-treat-org.freedesktop.DBus.Error.ServiceUnknown-.patch +resolve-fix-memleak.patch +shared-split-out-polkit-stuff-from-bus-util.c-bus-polkit..patch +bus-polkit-rename-return-error-parameter-to-ret_error.patch +polkit-reuse-some-common-bus-message-appending-code.patch +polkit-on-async-pk-requests-re-validate-action-details.patch +polkit-use-structured-initialization.patch +sd-bus-introduce-API-for-re-enqueuing-incoming-messages.patch +polkit-when-authorizing-via-PK-let-s-re-resolve-callback-.patch +Fix-typo-in-function-name.patch +basic-cap-list-parse-print-numerical-capabilities.patch +missing-Add-new-Linux-capabilities.patch +networkd-do-not-generate-MAC-for-bridge-device.patch +journal-do-not-trigger-assertion-when-journal_file_close-.patch +test-bpf-skip-test-when-run-inside-containers.patch +tests-skip-test-bpf-only-when-we-re-100-sure-it-s-run-in-.patch +core-make-sure-to-restore-the-control-command-id-too.patch +seccomp-allow-turning-off-of-seccomp-filtering-via-env-va.patch +basic-unit-name-do-not-use-strdupa-on-a-path.patch +debian/Use-Debian-specific-config-files.patch +debian/Bring-tmpfiles.d-tmp.conf-in-line-with-Debian-defaul.patch +debian/Make-run-lock-tmpfs-an-API-fs.patch +debian/Revert-udev-network-device-renaming-immediately-give.patch +debian/Add-support-for-TuxOnIce-hibernation.patch +debian/Re-enable-journal-forwarding-to-syslog.patch +debian/Don-t-enable-audit-by-default.patch +debian/Only-start-logind-if-dbus-is-installed.patch +debian/fsckd-daemon-for-inter-fsckd-communication.patch +debian/Skip-filesystem-check-if-already-done-by-the-initram.patch +debian/Revert-core-one-step-back-again-for-nspawn-we-actual.patch +debian/Revert-core-set-RLIMIT_CORE-to-unlimited-by-default.patch +debian/Revert-core-enable-TasksMax-for-all-services-by-default-a.patch +debian/Let-graphical-session-pre.target-be-manually-started.patch +debian/Add-env-variable-for-machine-ID-path.patch +debian/Drop-seccomp-system-call-filter-for-udev.patch diff --git a/debian/patches/shared-bus-util-drop-trusted-annotation-from-bus_open_sys.patch b/debian/patches/shared-bus-util-drop-trusted-annotation-from-bus_open_sys.patch new file mode 100644 index 0000000..bd736b6 --- /dev/null +++ b/debian/patches/shared-bus-util-drop-trusted-annotation-from-bus_open_sys.patch @@ -0,0 +1,32 @@ +From: =?utf-8?q?Zbigniew_J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl> +Date: Tue, 27 Aug 2019 19:00:34 +0200 +Subject: shared/bus-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. + +(cherry picked from commit 35e528018f315798d3bffcb592b32a0d8f5162bd) +--- + 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 cbcf698..9d31fba 100644 +--- a/src/shared/bus-util.c ++++ b/src/shared/bus-util.c +@@ -1696,10 +1696,6 @@ int bus_open_system_watch_bind_with_description(sd_bus **ret, const char *descri + if (r < 0) + return r; + +- r = sd_bus_set_trusted(bus, true); +- if (r < 0) +- return r; +- + r = sd_bus_negotiate_creds(bus, true, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_EFFECTIVE_CAPS); + if (r < 0) + return r; diff --git a/debian/patches/shared-seccomp-add-sync_file_range2.patch b/debian/patches/shared-seccomp-add-sync_file_range2.patch new file mode 100644 index 0000000..eb4f839 --- /dev/null +++ b/debian/patches/shared-seccomp-add-sync_file_range2.patch @@ -0,0 +1,24 @@ +From: =?utf-8?q?Zbigniew_J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl> +Date: Mon, 19 Aug 2019 08:51:39 +0200 +Subject: shared/seccomp: add sync_file_range2 + +Some architectures need the arguments to be reordered because of alignment +issues. Otherwise, it's the same as sync_file_range. + +(cherry picked from commit a8fb09f57395613d472d7b555db6e0ce802a8c84) +--- + src/shared/seccomp-util.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c +index cc58b3c..958128c 100644 +--- a/src/shared/seccomp-util.c ++++ b/src/shared/seccomp-util.c +@@ -756,6 +756,7 @@ const SyscallFilterSet syscall_filter_sets[_SYSCALL_FILTER_SET_MAX] = { + "msync\0" + "sync\0" + "sync_file_range\0" ++ "sync_file_range2\0" + "syncfs\0" + }, + [SYSCALL_FILTER_SET_SYSTEM_SERVICE] = { diff --git a/debian/patches/shared-split-out-polkit-stuff-from-bus-util.c-bus-polkit..patch b/debian/patches/shared-split-out-polkit-stuff-from-bus-util.c-bus-polkit..patch new file mode 100644 index 0000000..3a14551 --- /dev/null +++ b/debian/patches/shared-split-out-polkit-stuff-from-bus-util.c-bus-polkit..patch @@ -0,0 +1,1190 @@ +From: Lennart Poettering <lennart@poettering.net> +Date: Wed, 22 Jan 2020 11:39:22 +0100 +Subject: =?utf-8?q?shared=3A_split_out_polkit_stuff_from_bus-util=2Ec_?= + =?utf-8?q?=E2=86=92_bus-polkit=2Ec?= + +It's enough, complex stuff to warrant its own source file. + +No other changes, just splitting out. + +(cherry picked from commit 269e4d2d6b75329ae39a71ebe2c14500e03cda95) +(cherry picked from commit 0a19ff7004e4a567566a0a7be6b050cf34c0bfe5) +(cherry picked from commit 31a1d569db43af04669ec487f3e741ddc6d12969) +(cherry picked from commit a4722a8df23f6612c47f1bb848a6a7c81dcbdccb) +--- + src/core/dbus-unit.c | 1 + + src/core/dbus.c | 2 +- + src/hostname/hostnamed.c | 2 +- + src/import/importd.c | 2 +- + src/locale/keymap-util.c | 2 + + src/locale/localed.c | 2 +- + src/login/logind-dbus.c | 1 + + src/login/logind-seat-dbus.c | 1 + + src/login/logind-session-dbus.c | 1 + + src/login/logind-user-dbus.c | 1 + + src/login/logind.c | 2 +- + src/machine/image-dbus.c | 1 + + src/machine/machine-dbus.c | 1 + + src/machine/machined-dbus.c | 1 + + src/machine/machined.c | 2 +- + src/network/networkd-link-bus.c | 2 + + src/network/networkd-manager-bus.c | 3 + + src/network/networkd-manager.c | 1 + + src/portable/portabled-bus.c | 2 +- + src/portable/portabled-image-bus.c | 1 + + src/portable/portabled.c | 2 +- + src/resolve/resolved-bus.c | 1 + + src/resolve/resolved-dnssd-bus.c | 5 +- + src/resolve/resolved-link-bus.c | 1 + + src/resolve/resolved-manager.c | 2 +- + src/shared/bus-polkit.c | 358 +++++++++++++++++++++++++++++++++++++ + src/shared/bus-polkit.h | 11 ++ + src/shared/bus-util.c | 357 +----------------------------------- + src/shared/bus-util.h | 7 +- + src/shared/meson.build | 2 + + src/timedate/timedated.c | 2 +- + 31 files changed, 406 insertions(+), 373 deletions(-) + create mode 100644 src/shared/bus-polkit.c + create mode 100644 src/shared/bus-polkit.h + +diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c +index 17c2003..ce0fbdb 100644 +--- a/src/core/dbus-unit.c ++++ b/src/core/dbus-unit.c +@@ -5,6 +5,7 @@ + #include "alloc-util.h" + #include "bpf-firewall.h" + #include "bus-common-errors.h" ++#include "bus-polkit.h" + #include "cgroup-util.h" + #include "condition.h" + #include "dbus-job.h" +diff --git a/src/core/dbus.c b/src/core/dbus.c +index 255b86e..91c06ce 100644 +--- a/src/core/dbus.c ++++ b/src/core/dbus.c +@@ -10,7 +10,7 @@ + #include "bus-common-errors.h" + #include "bus-error.h" + #include "bus-internal.h" +-#include "bus-util.h" ++#include "bus-polkit.h" + #include "dbus-automount.h" + #include "dbus-cgroup.h" + #include "dbus-device.h" +diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c +index 7777450..9b98f32 100644 +--- a/src/hostname/hostnamed.c ++++ b/src/hostname/hostnamed.c +@@ -7,7 +7,7 @@ + + #include "alloc-util.h" + #include "bus-common-errors.h" +-#include "bus-util.h" ++#include "bus-polkit.h" + #include "def.h" + #include "env-file-label.h" + #include "env-file.h" +diff --git a/src/import/importd.c b/src/import/importd.c +index 2426933..15430d8 100644 +--- a/src/import/importd.c ++++ b/src/import/importd.c +@@ -7,7 +7,7 @@ + + #include "alloc-util.h" + #include "bus-common-errors.h" +-#include "bus-util.h" ++#include "bus-polkit.h" + #include "def.h" + #include "fd-util.h" + #include "float.h" +diff --git a/src/locale/keymap-util.c b/src/locale/keymap-util.c +index 6b6b32a..c203c7a 100644 +--- a/src/locale/keymap-util.c ++++ b/src/locale/keymap-util.c +@@ -6,7 +6,9 @@ + #include <unistd.h> + + #include "bus-util.h" ++#include "bus-polkit.h" + #include "def.h" ++#include "env-file-label.h" + #include "env-file.h" + #include "env-file-label.h" + #include "env-util.h" +diff --git a/src/locale/localed.c b/src/locale/localed.c +index f851d35..0bc02a0 100644 +--- a/src/locale/localed.c ++++ b/src/locale/localed.c +@@ -14,7 +14,7 @@ + #include "alloc-util.h" + #include "bus-error.h" + #include "bus-message.h" +-#include "bus-util.h" ++#include "bus-polkit.h" + #include "def.h" + #include "keymap-util.h" + #include "locale-util.h" +diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c +index b9ea370..91350fd 100644 +--- a/src/login/logind-dbus.c ++++ b/src/login/logind-dbus.c +@@ -12,6 +12,7 @@ + #include "audit-util.h" + #include "bus-common-errors.h" + #include "bus-error.h" ++#include "bus-polkit.h" + #include "bus-unit-util.h" + #include "bus-util.h" + #include "cgroup-util.h" +diff --git a/src/login/logind-seat-dbus.c b/src/login/logind-seat-dbus.c +index 6ee5a1c..28ea5b7 100644 +--- a/src/login/logind-seat-dbus.c ++++ b/src/login/logind-seat-dbus.c +@@ -6,6 +6,7 @@ + #include "alloc-util.h" + #include "bus-common-errors.h" + #include "bus-label.h" ++#include "bus-polkit.h" + #include "bus-util.h" + #include "logind-seat.h" + #include "logind.h" +diff --git a/src/login/logind-session-dbus.c b/src/login/logind-session-dbus.c +index df5bfba..bd5c1fe 100644 +--- a/src/login/logind-session-dbus.c ++++ b/src/login/logind-session-dbus.c +@@ -6,6 +6,7 @@ + #include "alloc-util.h" + #include "bus-common-errors.h" + #include "bus-label.h" ++#include "bus-polkit.h" + #include "bus-util.h" + #include "fd-util.h" + #include "logind-session-device.h" +diff --git a/src/login/logind-user-dbus.c b/src/login/logind-user-dbus.c +index fcaeba1..129696e 100644 +--- a/src/login/logind-user-dbus.c ++++ b/src/login/logind-user-dbus.c +@@ -4,6 +4,7 @@ + #include <string.h> + + #include "alloc-util.h" ++#include "bus-polkit.h" + #include "bus-util.h" + #include "format-util.h" + #include "logind-user.h" +diff --git a/src/login/logind.c b/src/login/logind.c +index 95ec0a5..171b898 100644 +--- a/src/login/logind.c ++++ b/src/login/logind.c +@@ -10,7 +10,7 @@ + + #include "alloc-util.h" + #include "bus-error.h" +-#include "bus-util.h" ++#include "bus-polkit.h" + #include "cgroup-util.h" + #include "def.h" + #include "device-util.h" +diff --git a/src/machine/image-dbus.c b/src/machine/image-dbus.c +index 7e7f0d5..1322f3e 100644 +--- a/src/machine/image-dbus.c ++++ b/src/machine/image-dbus.c +@@ -5,6 +5,7 @@ + + #include "alloc-util.h" + #include "bus-label.h" ++#include "bus-polkit.h" + #include "bus-util.h" + #include "copy.h" + #include "dissect-image.h" +diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c +index 7a558df..39905e5 100644 +--- a/src/machine/machine-dbus.c ++++ b/src/machine/machine-dbus.c +@@ -15,6 +15,7 @@ + #include "bus-common-errors.h" + #include "bus-internal.h" + #include "bus-label.h" ++#include "bus-polkit.h" + #include "bus-util.h" + #include "copy.h" + #include "env-file.h" +diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c +index fea9cc2..f00be23 100644 +--- a/src/machine/machined-dbus.c ++++ b/src/machine/machined-dbus.c +@@ -9,6 +9,7 @@ + #include "alloc-util.h" + #include "btrfs-util.h" + #include "bus-common-errors.h" ++#include "bus-polkit.h" + #include "bus-util.h" + #include "cgroup-util.h" + #include "fd-util.h" +diff --git a/src/machine/machined.c b/src/machine/machined.c +index 0b92b1c..e3456d8 100644 +--- a/src/machine/machined.c ++++ b/src/machine/machined.c +@@ -8,7 +8,7 @@ + + #include "alloc-util.h" + #include "bus-error.h" +-#include "bus-util.h" ++#include "bus-polkit.h" + #include "cgroup-util.h" + #include "dirent-util.h" + #include "fd-util.h" +diff --git a/src/network/networkd-link-bus.c b/src/network/networkd-link-bus.c +index 0dbcd86..beee910 100644 +--- a/src/network/networkd-link-bus.c ++++ b/src/network/networkd-link-bus.c +@@ -1,6 +1,8 @@ + /* SPDX-License-Identifier: LGPL-2.1+ */ + + #include "alloc-util.h" ++#include "bus-common-errors.h" ++#include "bus-polkit.h" + #include "bus-util.h" + #include "networkd-link.h" + #include "networkd-manager.h" +diff --git a/src/network/networkd-manager-bus.c b/src/network/networkd-manager-bus.c +index 8c52783..7628878 100644 +--- a/src/network/networkd-manager-bus.c ++++ b/src/network/networkd-manager-bus.c +@@ -1,7 +1,10 @@ + /* SPDX-License-Identifier: LGPL-2.1+ */ + + #include "alloc-util.h" ++#include "bus-common-errors.h" ++#include "bus-polkit.h" + #include "bus-util.h" ++#include "networkd-link.h" + #include "networkd-manager.h" + #include "strv.h" + +diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c +index acb9a75..bd29fd0 100644 +--- a/src/network/networkd-manager.c ++++ b/src/network/networkd-manager.c +@@ -9,6 +9,7 @@ + #include "sd-netlink.h" + + #include "alloc-util.h" ++#include "bus-polkit.h" + #include "bus-util.h" + #include "conf-parser.h" + #include "def.h" +diff --git a/src/portable/portabled-bus.c b/src/portable/portabled-bus.c +index 3cbdb0b..708ec94 100644 +--- a/src/portable/portabled-bus.c ++++ b/src/portable/portabled-bus.c +@@ -3,7 +3,7 @@ + #include "alloc-util.h" + #include "btrfs-util.h" + #include "bus-common-errors.h" +-#include "bus-util.h" ++#include "bus-polkit.h" + #include "fd-util.h" + #include "io-util.h" + #include "machine-image.h" +diff --git a/src/portable/portabled-image-bus.c b/src/portable/portabled-image-bus.c +index 3605598..beebcf8 100644 +--- a/src/portable/portabled-image-bus.c ++++ b/src/portable/portabled-image-bus.c +@@ -3,6 +3,7 @@ + #include "alloc-util.h" + #include "bus-common-errors.h" + #include "bus-label.h" ++#include "bus-polkit.h" + #include "bus-util.h" + #include "fd-util.h" + #include "fileio.h" +diff --git a/src/portable/portabled.c b/src/portable/portabled.c +index 49a359f..f5a34ff 100644 +--- a/src/portable/portabled.c ++++ b/src/portable/portabled.c +@@ -4,7 +4,7 @@ + #include "sd-daemon.h" + + #include "alloc-util.h" +-#include "bus-util.h" ++#include "bus-polkit.h" + #include "def.h" + #include "main-func.h" + #include "portabled-bus.h" +diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c +index 5b547ba..1638d3b 100644 +--- a/src/resolve/resolved-bus.c ++++ b/src/resolve/resolved-bus.c +@@ -2,6 +2,7 @@ + + #include "alloc-util.h" + #include "bus-common-errors.h" ++#include "bus-polkit.h" + #include "bus-util.h" + #include "dns-domain.h" + #include "missing_capability.h" +diff --git a/src/resolve/resolved-dnssd-bus.c b/src/resolve/resolved-dnssd-bus.c +index 24bb37b..f7dcb3b 100644 +--- a/src/resolve/resolved-dnssd-bus.c ++++ b/src/resolve/resolved-dnssd-bus.c +@@ -1,9 +1,10 @@ ++/* SPDX-License-Identifier: LGPL-2.1+ */ + + #include "alloc-util.h" +-#include "bus-util.h" ++#include "bus-polkit.h" + #include "missing_capability.h" +-#include "resolved-dnssd.h" + #include "resolved-dnssd-bus.h" ++#include "resolved-dnssd.h" + #include "resolved-link.h" + #include "strv.h" + #include "user-util.h" +diff --git a/src/resolve/resolved-link-bus.c b/src/resolve/resolved-link-bus.c +index 96093ff..53f017c 100644 +--- a/src/resolve/resolved-link-bus.c ++++ b/src/resolve/resolved-link-bus.c +@@ -2,6 +2,7 @@ + + #include "alloc-util.h" + #include "bus-common-errors.h" ++#include "bus-polkit.h" + #include "bus-util.h" + #include "parse-util.h" + #include "resolve-util.h" +diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c +index 2017b0e..422ec23 100644 +--- a/src/resolve/resolved-manager.c ++++ b/src/resolve/resolved-manager.c +@@ -11,7 +11,7 @@ + + #include "af-list.h" + #include "alloc-util.h" +-#include "bus-util.h" ++#include "bus-polkit.h" + #include "dirent-util.h" + #include "dns-domain.h" + #include "fd-util.h" +diff --git a/src/shared/bus-polkit.c b/src/shared/bus-polkit.c +new file mode 100644 +index 0000000..da4aee5 +--- /dev/null ++++ b/src/shared/bus-polkit.c +@@ -0,0 +1,358 @@ ++/* SPDX-License-Identifier: LGPL-2.1+ */ ++ ++#include "bus-internal.h" ++#include "bus-message.h" ++#include "bus-polkit.h" ++#include "strv.h" ++#include "user-util.h" ++ ++static int check_good_user(sd_bus_message *m, uid_t good_user) { ++ _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; ++ uid_t sender_uid; ++ int r; ++ ++ assert(m); ++ ++ if (good_user == UID_INVALID) ++ return 0; ++ ++ r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_EUID, &creds); ++ if (r < 0) ++ return r; ++ ++ /* Don't trust augmented credentials for authorization */ ++ assert_return((sd_bus_creds_get_augmented_mask(creds) & SD_BUS_CREDS_EUID) == 0, -EPERM); ++ ++ r = sd_bus_creds_get_euid(creds, &sender_uid); ++ if (r < 0) ++ return r; ++ ++ return sender_uid == good_user; ++} ++ ++int bus_test_polkit( ++ sd_bus_message *call, ++ int capability, ++ const char *action, ++ const char **details, ++ uid_t good_user, ++ bool *_challenge, ++ sd_bus_error *e) { ++ ++ int r; ++ ++ assert(call); ++ assert(action); ++ ++ /* Tests non-interactively! */ ++ ++ r = check_good_user(call, good_user); ++ if (r != 0) ++ return r; ++ ++ r = sd_bus_query_sender_privilege(call, capability); ++ if (r < 0) ++ return r; ++ else if (r > 0) ++ return 1; ++#if ENABLE_POLKIT ++ else { ++ _cleanup_(sd_bus_message_unrefp) sd_bus_message *request = NULL; ++ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; ++ int authorized = false, challenge = false; ++ const char *sender, **k, **v; ++ ++ sender = sd_bus_message_get_sender(call); ++ if (!sender) ++ return -EBADMSG; ++ ++ r = sd_bus_message_new_method_call( ++ call->bus, ++ &request, ++ "org.freedesktop.PolicyKit1", ++ "/org/freedesktop/PolicyKit1/Authority", ++ "org.freedesktop.PolicyKit1.Authority", ++ "CheckAuthorization"); ++ if (r < 0) ++ return r; ++ ++ r = sd_bus_message_append( ++ request, ++ "(sa{sv})s", ++ "system-bus-name", 1, "name", "s", sender, ++ action); ++ if (r < 0) ++ return r; ++ ++ r = sd_bus_message_open_container(request, 'a', "{ss}"); ++ if (r < 0) ++ return r; ++ ++ STRV_FOREACH_PAIR(k, v, details) { ++ r = sd_bus_message_append(request, "{ss}", *k, *v); ++ if (r < 0) ++ return r; ++ } ++ ++ r = sd_bus_message_close_container(request); ++ if (r < 0) ++ return r; ++ ++ r = sd_bus_message_append(request, "us", 0, NULL); ++ if (r < 0) ++ return r; ++ ++ r = sd_bus_call(call->bus, request, 0, e, &reply); ++ if (r < 0) { ++ /* Treat no PK available as access denied */ ++ if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN)) { ++ sd_bus_error_free(e); ++ return -EACCES; ++ } ++ ++ return r; ++ } ++ ++ r = sd_bus_message_enter_container(reply, 'r', "bba{ss}"); ++ if (r < 0) ++ return r; ++ ++ r = sd_bus_message_read(reply, "bb", &authorized, &challenge); ++ if (r < 0) ++ return r; ++ ++ if (authorized) ++ return 1; ++ ++ if (_challenge) { ++ *_challenge = challenge; ++ return 0; ++ } ++ } ++#endif ++ ++ return -EACCES; ++} ++ ++#if ENABLE_POLKIT ++ ++typedef struct AsyncPolkitQuery { ++ sd_bus_message *request, *reply; ++ sd_bus_message_handler_t callback; ++ void *userdata; ++ sd_bus_slot *slot; ++ Hashmap *registry; ++} AsyncPolkitQuery; ++ ++static void async_polkit_query_free(AsyncPolkitQuery *q) { ++ ++ if (!q) ++ return; ++ ++ sd_bus_slot_unref(q->slot); ++ ++ if (q->registry && q->request) ++ hashmap_remove(q->registry, q->request); ++ ++ sd_bus_message_unref(q->request); ++ sd_bus_message_unref(q->reply); ++ ++ free(q); ++} ++ ++static int async_polkit_callback(sd_bus_message *reply, void *userdata, sd_bus_error *error) { ++ _cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL; ++ AsyncPolkitQuery *q = userdata; ++ int r; ++ ++ assert(reply); ++ assert(q); ++ ++ q->slot = sd_bus_slot_unref(q->slot); ++ q->reply = sd_bus_message_ref(reply); ++ ++ r = sd_bus_message_rewind(q->request, true); ++ if (r < 0) { ++ r = sd_bus_reply_method_errno(q->request, r, NULL); ++ goto finish; ++ } ++ ++ r = q->callback(q->request, q->userdata, &error_buffer); ++ r = bus_maybe_reply_error(q->request, r, &error_buffer); ++ ++finish: ++ async_polkit_query_free(q); ++ ++ return r; ++} ++ ++#endif ++ ++int bus_verify_polkit_async( ++ sd_bus_message *call, ++ int capability, ++ const char *action, ++ const char **details, ++ bool interactive, ++ uid_t good_user, ++ Hashmap **registry, ++ sd_bus_error *error) { ++ ++#if ENABLE_POLKIT ++ _cleanup_(sd_bus_message_unrefp) sd_bus_message *pk = NULL; ++ AsyncPolkitQuery *q; ++ const char *sender, **k, **v; ++ sd_bus_message_handler_t callback; ++ void *userdata; ++ int c; ++#endif ++ int r; ++ ++ assert(call); ++ assert(action); ++ assert(registry); ++ ++ r = check_good_user(call, good_user); ++ if (r != 0) ++ return r; ++ ++#if ENABLE_POLKIT ++ q = hashmap_get(*registry, call); ++ if (q) { ++ int authorized, challenge; ++ ++ /* This is the second invocation of this function, and ++ * there's already a response from polkit, let's ++ * process it */ ++ assert(q->reply); ++ ++ if (sd_bus_message_is_method_error(q->reply, NULL)) { ++ const sd_bus_error *e; ++ ++ e = sd_bus_message_get_error(q->reply); ++ ++ /* Treat no PK available as access denied */ ++ if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN) || ++ sd_bus_error_has_name(e, SD_BUS_ERROR_NAME_HAS_NO_OWNER)) ++ return -EACCES; ++ ++ /* Copy error from polkit reply */ ++ sd_bus_error_copy(error, e); ++ return -sd_bus_error_get_errno(e); ++ } ++ ++ r = sd_bus_message_enter_container(q->reply, 'r', "bba{ss}"); ++ if (r >= 0) ++ r = sd_bus_message_read(q->reply, "bb", &authorized, &challenge); ++ if (r < 0) ++ return r; ++ ++ if (authorized) ++ return 1; ++ ++ if (challenge) ++ return sd_bus_error_set(error, SD_BUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED, "Interactive authentication required."); ++ ++ return -EACCES; ++ } ++#endif ++ ++ r = sd_bus_query_sender_privilege(call, capability); ++ if (r < 0) ++ return r; ++ else if (r > 0) ++ return 1; ++ ++#if ENABLE_POLKIT ++ if (sd_bus_get_current_message(call->bus) != call) ++ return -EINVAL; ++ ++ callback = sd_bus_get_current_handler(call->bus); ++ if (!callback) ++ return -EINVAL; ++ ++ userdata = sd_bus_get_current_userdata(call->bus); ++ ++ sender = sd_bus_message_get_sender(call); ++ if (!sender) ++ return -EBADMSG; ++ ++ c = sd_bus_message_get_allow_interactive_authorization(call); ++ if (c < 0) ++ return c; ++ if (c > 0) ++ interactive = true; ++ ++ r = hashmap_ensure_allocated(registry, NULL); ++ if (r < 0) ++ return r; ++ ++ r = sd_bus_message_new_method_call( ++ call->bus, ++ &pk, ++ "org.freedesktop.PolicyKit1", ++ "/org/freedesktop/PolicyKit1/Authority", ++ "org.freedesktop.PolicyKit1.Authority", ++ "CheckAuthorization"); ++ if (r < 0) ++ return r; ++ ++ r = sd_bus_message_append( ++ pk, ++ "(sa{sv})s", ++ "system-bus-name", 1, "name", "s", sender, ++ action); ++ if (r < 0) ++ return r; ++ ++ r = sd_bus_message_open_container(pk, 'a', "{ss}"); ++ if (r < 0) ++ return r; ++ ++ STRV_FOREACH_PAIR(k, v, details) { ++ r = sd_bus_message_append(pk, "{ss}", *k, *v); ++ if (r < 0) ++ return r; ++ } ++ ++ r = sd_bus_message_close_container(pk); ++ if (r < 0) ++ return r; ++ ++ r = sd_bus_message_append(pk, "us", interactive, NULL); ++ if (r < 0) ++ return r; ++ ++ q = new0(AsyncPolkitQuery, 1); ++ if (!q) ++ return -ENOMEM; ++ ++ q->request = sd_bus_message_ref(call); ++ q->callback = callback; ++ q->userdata = userdata; ++ ++ r = hashmap_put(*registry, call, q); ++ if (r < 0) { ++ async_polkit_query_free(q); ++ return r; ++ } ++ ++ q->registry = *registry; ++ ++ r = sd_bus_call_async(call->bus, &q->slot, pk, async_polkit_callback, q, 0); ++ if (r < 0) { ++ async_polkit_query_free(q); ++ return r; ++ } ++ ++ return 0; ++#endif ++ ++ return -EACCES; ++} ++ ++void bus_verify_polkit_async_registry_free(Hashmap *registry) { ++#if ENABLE_POLKIT ++ hashmap_free_with_destructor(registry, async_polkit_query_free); ++#endif ++} +diff --git a/src/shared/bus-polkit.h b/src/shared/bus-polkit.h +new file mode 100644 +index 0000000..29b3923 +--- /dev/null ++++ b/src/shared/bus-polkit.h +@@ -0,0 +1,11 @@ ++/* SPDX-License-Identifier: LGPL-2.1+ */ ++#pragma once ++ ++#include "sd-bus.h" ++ ++#include "hashmap.h" ++ ++int bus_test_polkit(sd_bus_message *call, int capability, const char *action, const char **details, uid_t good_user, bool *_challenge, sd_bus_error *e); ++ ++int bus_verify_polkit_async(sd_bus_message *call, int capability, const char *action, const char **details, bool interactive, uid_t good_user, Hashmap **registry, sd_bus_error *error); ++void bus_verify_polkit_async_registry_free(Hashmap *registry); +diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c +index a406dd8..c9d7e76 100644 +--- a/src/shared/bus-util.c ++++ b/src/shared/bus-util.c +@@ -11,7 +11,6 @@ + #include <sys/socket.h> + #include <unistd.h> + +-#include "sd-bus-protocol.h" + #include "sd-bus.h" + #include "sd-daemon.h" + #include "sd-event.h" +@@ -24,15 +23,14 @@ + #include "bus-util.h" + #include "cap-list.h" + #include "cgroup-util.h" +-#include "def.h" +-#include "escape.h" +-#include "fd-util.h" + #include "missing.h" + #include "mountpoint-util.h" + #include "nsflags.h" + #include "parse-util.h" + #include "proc-cmdline.h" ++#include "path-util.h" + #include "rlimit-util.h" ++#include "socket-util.h" + #include "stdio-util.h" + #include "strv.h" + #include "user-util.h" +@@ -187,357 +185,6 @@ int bus_name_has_owner(sd_bus *c, const char *name, sd_bus_error *error) { + return has_owner; + } + +-static int check_good_user(sd_bus_message *m, uid_t good_user) { +- _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; +- uid_t sender_uid; +- int r; +- +- assert(m); +- +- if (good_user == UID_INVALID) +- return 0; +- +- r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_EUID, &creds); +- if (r < 0) +- return r; +- +- /* Don't trust augmented credentials for authorization */ +- assert_return((sd_bus_creds_get_augmented_mask(creds) & SD_BUS_CREDS_EUID) == 0, -EPERM); +- +- r = sd_bus_creds_get_euid(creds, &sender_uid); +- if (r < 0) +- return r; +- +- return sender_uid == good_user; +-} +- +-int bus_test_polkit( +- sd_bus_message *call, +- int capability, +- const char *action, +- const char **details, +- uid_t good_user, +- bool *_challenge, +- sd_bus_error *e) { +- +- int r; +- +- assert(call); +- assert(action); +- +- /* Tests non-interactively! */ +- +- r = check_good_user(call, good_user); +- if (r != 0) +- return r; +- +- r = sd_bus_query_sender_privilege(call, capability); +- if (r < 0) +- return r; +- else if (r > 0) +- return 1; +-#if ENABLE_POLKIT +- else { +- _cleanup_(sd_bus_message_unrefp) sd_bus_message *request = NULL; +- _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; +- int authorized = false, challenge = false; +- const char *sender, **k, **v; +- +- sender = sd_bus_message_get_sender(call); +- if (!sender) +- return -EBADMSG; +- +- r = sd_bus_message_new_method_call( +- call->bus, +- &request, +- "org.freedesktop.PolicyKit1", +- "/org/freedesktop/PolicyKit1/Authority", +- "org.freedesktop.PolicyKit1.Authority", +- "CheckAuthorization"); +- if (r < 0) +- return r; +- +- r = sd_bus_message_append( +- request, +- "(sa{sv})s", +- "system-bus-name", 1, "name", "s", sender, +- action); +- if (r < 0) +- return r; +- +- r = sd_bus_message_open_container(request, 'a', "{ss}"); +- if (r < 0) +- return r; +- +- STRV_FOREACH_PAIR(k, v, details) { +- r = sd_bus_message_append(request, "{ss}", *k, *v); +- if (r < 0) +- return r; +- } +- +- r = sd_bus_message_close_container(request); +- if (r < 0) +- return r; +- +- r = sd_bus_message_append(request, "us", 0, NULL); +- if (r < 0) +- return r; +- +- r = sd_bus_call(call->bus, request, 0, e, &reply); +- if (r < 0) { +- /* Treat no PK available as access denied */ +- if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN)) { +- sd_bus_error_free(e); +- return -EACCES; +- } +- +- return r; +- } +- +- r = sd_bus_message_enter_container(reply, 'r', "bba{ss}"); +- if (r < 0) +- return r; +- +- r = sd_bus_message_read(reply, "bb", &authorized, &challenge); +- if (r < 0) +- return r; +- +- if (authorized) +- return 1; +- +- if (_challenge) { +- *_challenge = challenge; +- return 0; +- } +- } +-#endif +- +- return -EACCES; +-} +- +-#if ENABLE_POLKIT +- +-typedef struct AsyncPolkitQuery { +- sd_bus_message *request, *reply; +- sd_bus_message_handler_t callback; +- void *userdata; +- sd_bus_slot *slot; +- Hashmap *registry; +-} AsyncPolkitQuery; +- +-static void async_polkit_query_free(AsyncPolkitQuery *q) { +- +- if (!q) +- return; +- +- sd_bus_slot_unref(q->slot); +- +- if (q->registry && q->request) +- hashmap_remove(q->registry, q->request); +- +- sd_bus_message_unref(q->request); +- sd_bus_message_unref(q->reply); +- +- free(q); +-} +- +-static int async_polkit_callback(sd_bus_message *reply, void *userdata, sd_bus_error *error) { +- _cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL; +- AsyncPolkitQuery *q = userdata; +- int r; +- +- assert(reply); +- assert(q); +- +- q->slot = sd_bus_slot_unref(q->slot); +- q->reply = sd_bus_message_ref(reply); +- +- r = sd_bus_message_rewind(q->request, true); +- if (r < 0) { +- r = sd_bus_reply_method_errno(q->request, r, NULL); +- goto finish; +- } +- +- r = q->callback(q->request, q->userdata, &error_buffer); +- r = bus_maybe_reply_error(q->request, r, &error_buffer); +- +-finish: +- async_polkit_query_free(q); +- +- return r; +-} +- +-#endif +- +-int bus_verify_polkit_async( +- sd_bus_message *call, +- int capability, +- const char *action, +- const char **details, +- bool interactive, +- uid_t good_user, +- Hashmap **registry, +- sd_bus_error *error) { +- +-#if ENABLE_POLKIT +- _cleanup_(sd_bus_message_unrefp) sd_bus_message *pk = NULL; +- AsyncPolkitQuery *q; +- const char *sender, **k, **v; +- sd_bus_message_handler_t callback; +- void *userdata; +- int c; +-#endif +- int r; +- +- assert(call); +- assert(action); +- assert(registry); +- +- r = check_good_user(call, good_user); +- if (r != 0) +- return r; +- +-#if ENABLE_POLKIT +- q = hashmap_get(*registry, call); +- if (q) { +- int authorized, challenge; +- +- /* This is the second invocation of this function, and +- * there's already a response from polkit, let's +- * process it */ +- assert(q->reply); +- +- if (sd_bus_message_is_method_error(q->reply, NULL)) { +- const sd_bus_error *e; +- +- e = sd_bus_message_get_error(q->reply); +- +- /* Treat no PK available as access denied */ +- if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN)) +- return -EACCES; +- +- /* Copy error from polkit reply */ +- sd_bus_error_copy(error, e); +- return -sd_bus_error_get_errno(e); +- } +- +- r = sd_bus_message_enter_container(q->reply, 'r', "bba{ss}"); +- if (r >= 0) +- r = sd_bus_message_read(q->reply, "bb", &authorized, &challenge); +- +- if (r < 0) +- return r; +- +- if (authorized) +- return 1; +- +- if (challenge) +- return sd_bus_error_set(error, SD_BUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED, "Interactive authentication required."); +- +- return -EACCES; +- } +-#endif +- +- r = sd_bus_query_sender_privilege(call, capability); +- if (r < 0) +- return r; +- else if (r > 0) +- return 1; +- +-#if ENABLE_POLKIT +- if (sd_bus_get_current_message(call->bus) != call) +- return -EINVAL; +- +- callback = sd_bus_get_current_handler(call->bus); +- if (!callback) +- return -EINVAL; +- +- userdata = sd_bus_get_current_userdata(call->bus); +- +- sender = sd_bus_message_get_sender(call); +- if (!sender) +- return -EBADMSG; +- +- c = sd_bus_message_get_allow_interactive_authorization(call); +- if (c < 0) +- return c; +- if (c > 0) +- interactive = true; +- +- r = hashmap_ensure_allocated(registry, NULL); +- if (r < 0) +- return r; +- +- r = sd_bus_message_new_method_call( +- call->bus, +- &pk, +- "org.freedesktop.PolicyKit1", +- "/org/freedesktop/PolicyKit1/Authority", +- "org.freedesktop.PolicyKit1.Authority", +- "CheckAuthorization"); +- if (r < 0) +- return r; +- +- r = sd_bus_message_append( +- pk, +- "(sa{sv})s", +- "system-bus-name", 1, "name", "s", sender, +- action); +- if (r < 0) +- return r; +- +- r = sd_bus_message_open_container(pk, 'a', "{ss}"); +- if (r < 0) +- return r; +- +- STRV_FOREACH_PAIR(k, v, details) { +- r = sd_bus_message_append(pk, "{ss}", *k, *v); +- if (r < 0) +- return r; +- } +- +- r = sd_bus_message_close_container(pk); +- if (r < 0) +- return r; +- +- r = sd_bus_message_append(pk, "us", interactive, NULL); +- if (r < 0) +- return r; +- +- q = new0(AsyncPolkitQuery, 1); +- if (!q) +- return -ENOMEM; +- +- q->request = sd_bus_message_ref(call); +- q->callback = callback; +- q->userdata = userdata; +- +- r = hashmap_put(*registry, call, q); +- if (r < 0) { +- async_polkit_query_free(q); +- return r; +- } +- +- q->registry = *registry; +- +- r = sd_bus_call_async(call->bus, &q->slot, pk, async_polkit_callback, q, 0); +- if (r < 0) { +- async_polkit_query_free(q); +- return r; +- } +- +- return 0; +-#endif +- +- return -EACCES; +-} +- +-void bus_verify_polkit_async_registry_free(Hashmap *registry) { +-#if ENABLE_POLKIT +- hashmap_free_with_destructor(registry, async_polkit_query_free); +-#endif +-} +- + int bus_check_peercred(sd_bus *c) { + struct ucred ucred; + int fd, r; +diff --git a/src/shared/bus-util.h b/src/shared/bus-util.h +index 71c248f..c9cbf76 100644 +--- a/src/shared/bus-util.h ++++ b/src/shared/bus-util.h +@@ -9,8 +9,8 @@ + #include "sd-bus.h" + #include "sd-event.h" + +-#include "hashmap.h" + #include "macro.h" ++#include "set.h" + #include "string-util.h" + + typedef enum BusTransport { +@@ -51,11 +51,6 @@ int bus_name_has_owner(sd_bus *c, const char *name, sd_bus_error *error); + + int bus_check_peercred(sd_bus *c); + +-int bus_test_polkit(sd_bus_message *call, int capability, const char *action, const char **details, uid_t good_user, bool *_challenge, sd_bus_error *e); +- +-int bus_verify_polkit_async(sd_bus_message *call, int capability, const char *action, const char **details, bool interactive, uid_t good_user, Hashmap **registry, sd_bus_error *error); +-void bus_verify_polkit_async_registry_free(Hashmap *registry); +- + int bus_connect_system_systemd(sd_bus **_bus); + int bus_connect_user_systemd(sd_bus **_bus); + +diff --git a/src/shared/meson.build b/src/shared/meson.build +index 99d6ba1..f6d1092 100644 +--- a/src/shared/meson.build ++++ b/src/shared/meson.build +@@ -25,6 +25,8 @@ shared_sources = files(''' + bus-unit-util.h + bus-util.c + bus-util.h ++ bus-polkit.c ++ bus-polkit.h + calendarspec.c + calendarspec.h + cgroup-show.c +diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c +index 324d4a4..398d4f4 100644 +--- a/src/timedate/timedated.c ++++ b/src/timedate/timedated.c +@@ -11,7 +11,7 @@ + #include "alloc-util.h" + #include "bus-common-errors.h" + #include "bus-error.h" +-#include "bus-util.h" ++#include "bus-polkit.h" + #include "clock-util.h" + #include "def.h" + #include "fileio-label.h" diff --git a/debian/patches/sysctl-util-add-sysctl_read_ip_property.patch b/debian/patches/sysctl-util-add-sysctl_read_ip_property.patch new file mode 100644 index 0000000..b6adfb6 --- /dev/null +++ b/debian/patches/sysctl-util-add-sysctl_read_ip_property.patch @@ -0,0 +1,49 @@ +From: Yu Watanabe <watanabe.yu+github@gmail.com> +Date: Mon, 18 Feb 2019 14:41:43 +0900 +Subject: sysctl-util: add sysctl_read_ip_property() + +(cherry picked from commit a6b3b0aace152b77682d68d99b3e41580c955efb) +--- + src/shared/sysctl-util.c | 22 ++++++++++++++++++++++ + src/shared/sysctl-util.h | 1 + + 2 files changed, 23 insertions(+) + +diff --git a/src/shared/sysctl-util.c b/src/shared/sysctl-util.c +index 480e6c3..ba89489 100644 +--- a/src/shared/sysctl-util.c ++++ b/src/shared/sysctl-util.c +@@ -69,3 +69,25 @@ int sysctl_read(const char *property, char **content) { + p = strjoina("/proc/sys/", property); + return read_full_file(p, content, NULL); + } ++ ++int sysctl_read_ip_property(int af, const char *ifname, const char *property, char **ret) { ++ _cleanup_free_ char *value = NULL; ++ const char *p; ++ int r; ++ ++ assert(IN_SET(af, AF_INET, AF_INET6)); ++ assert(property); ++ ++ p = strjoina("/proc/sys/net/ipv", af == AF_INET ? "4" : "6", ++ ifname ? "/conf/" : "", strempty(ifname), ++ property[0] == '/' ? "" : "/", property); ++ ++ r = read_one_line_file(p, &value); ++ if (r < 0) ++ return r; ++ ++ if (ret) ++ *ret = TAKE_PTR(value); ++ ++ return r; ++} +diff --git a/src/shared/sysctl-util.h b/src/shared/sysctl-util.h +index fd7c78b..22f52f8 100644 +--- a/src/shared/sysctl-util.h ++++ b/src/shared/sysctl-util.h +@@ -5,3 +5,4 @@ char *sysctl_normalize(char *s); + int sysctl_read(const char *property, char **value); + int sysctl_write(const char *property, const char *value); + ++int sysctl_read_ip_property(int af, const char *ifname, const char *property, char **ret); diff --git a/debian/patches/systemctl-restore-systemctl-reboot-ARG-functionality.patch b/debian/patches/systemctl-restore-systemctl-reboot-ARG-functionality.patch new file mode 100644 index 0000000..b10ee8b --- /dev/null +++ b/debian/patches/systemctl-restore-systemctl-reboot-ARG-functionality.patch @@ -0,0 +1,108 @@ +From: =?utf-8?b?VmVzYSBKw6TDpHNrZWzDpGluZW4=?= + <vesa.jaaskelainen@vaisala.com> +Date: Sat, 9 Mar 2019 22:30:45 +0200 +Subject: systemctl: restore "systemctl reboot ARG" functionality + +Commit d85515edcf9700dc068201ab9f7103f04f3b25b2 changed logic how reboot is +executed. That commit changed behavior to use emergency action reboot code path +to perform the reboot. + +This inadvertently broke rebooting with argument: +$ systemctl reboot custom-reason + +Restore original behavior so that if reboot service unit similar to +systemd-reboot.service is executed it is possible to override reboot reason +with "systemctl reboot ARG". + +When "systemctl reboot ARG" is executed ARG is placed in file +/run/systemd/reboot-param and reboot is issued using logind's Reboot +dbus-service. + +If RebootArgument is specified in systemd-reboot.service it takes precedence +over what systemctl sets. + +Fixes: #11828 +(cherry picked from commit 77defcf5382a557189350f928967d676510e362c) +--- + src/core/emergency-action.c | 4 ++-- + src/shared/reboot-util.c | 5 ++++- + src/shared/reboot-util.h | 2 +- + src/systemctl/systemctl.c | 4 ++-- + 4 files changed, 9 insertions(+), 6 deletions(-) + +diff --git a/src/core/emergency-action.c b/src/core/emergency-action.c +index f98b0de..52edec0 100644 +--- a/src/core/emergency-action.c ++++ b/src/core/emergency-action.c +@@ -47,7 +47,7 @@ int emergency_action( + case EMERGENCY_ACTION_REBOOT: + log_and_status(m, warn, "Rebooting", reason); + +- (void) update_reboot_parameter_and_warn(reboot_arg); ++ (void) update_reboot_parameter_and_warn(reboot_arg, true); + (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_REBOOT_TARGET, JOB_REPLACE_IRREVERSIBLY, NULL); + + break; +@@ -55,7 +55,7 @@ int emergency_action( + case EMERGENCY_ACTION_REBOOT_FORCE: + log_and_status(m, warn, "Forcibly rebooting", reason); + +- (void) update_reboot_parameter_and_warn(reboot_arg); ++ (void) update_reboot_parameter_and_warn(reboot_arg, true); + m->objective = MANAGER_REBOOT; + + break; +diff --git a/src/shared/reboot-util.c b/src/shared/reboot-util.c +index ca40159..6d5eee0 100644 +--- a/src/shared/reboot-util.c ++++ b/src/shared/reboot-util.c +@@ -12,10 +12,13 @@ + #include "umask-util.h" + #include "virt.h" + +-int update_reboot_parameter_and_warn(const char *parameter) { ++int update_reboot_parameter_and_warn(const char *parameter, bool keep) { + int r; + + if (isempty(parameter)) { ++ if (keep) ++ return 0; ++ + if (unlink("/run/systemd/reboot-param") < 0) { + if (errno == ENOENT) + return 0; +diff --git a/src/shared/reboot-util.h b/src/shared/reboot-util.h +index d459333..ac59b7d 100644 +--- a/src/shared/reboot-util.h ++++ b/src/shared/reboot-util.h +@@ -1,7 +1,7 @@ + /* SPDX-License-Identifier: LGPL-2.1+ */ + #pragma once + +-int update_reboot_parameter_and_warn(const char *parameter); ++int update_reboot_parameter_and_warn(const char *parameter, bool keep); + + typedef enum RebootFlags { + REBOOT_LOG = 1 << 0, /* log about what we are going to do and all errors */ +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index 63dae2c..d05219d 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -3634,7 +3634,7 @@ static int start_special(int argc, char *argv[], void *userdata) { + return r; + + if (a == ACTION_REBOOT && argc > 1) { +- r = update_reboot_parameter_and_warn(argv[1]); ++ r = update_reboot_parameter_and_warn(argv[1], false); + if (r < 0) + return r; + +@@ -8005,7 +8005,7 @@ static int halt_parse_argv(int argc, char *argv[]) { + } + + if (arg_action == ACTION_REBOOT && (argc == optind || argc == optind + 1)) { +- r = update_reboot_parameter_and_warn(argc == optind + 1 ? argv[optind] : NULL); ++ r = update_reboot_parameter_and_warn(argc == optind + 1 ? argv[optind] : NULL, false); + if (r < 0) + return r; + } else if (optind < argc) diff --git a/debian/patches/test-bpf-skip-test-when-run-inside-containers.patch b/debian/patches/test-bpf-skip-test-when-run-inside-containers.patch new file mode 100644 index 0000000..874daa2 --- /dev/null +++ b/debian/patches/test-bpf-skip-test-when-run-inside-containers.patch @@ -0,0 +1,41 @@ +From: Michael Biebl <biebl@debian.org> +Date: Sun, 19 May 2019 20:57:07 +0200 +Subject: test-bpf: skip test when run inside containers + +The test reliably fails inside LXC and Docker when run on a new enough +kernel. It's unclear whether this is a kernel, LXC/Docker or systemd +issue and apparently there is no real interest to get this fixed, so +let's skip this test. +As this also covers Travis CI, there is no need for this additional +check anymore. + +See https://github.com/systemd/systemd/issues/9666 + +(cherry picked from commit 98a3c188a1511caae422b2c891f3cc016824eb81) +--- + src/test/test-bpf.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/src/test/test-bpf.c b/src/test/test-bpf.c +index cd8d68f..eb1d8d7 100644 +--- a/src/test/test-bpf.c ++++ b/src/test/test-bpf.c +@@ -14,6 +14,7 @@ + #include "test-helper.h" + #include "tests.h" + #include "unit.h" ++#include "virt.h" + + /* We use the same limit here that PID 1 bumps RLIMIT_MEMLOCK to if it can */ + #define CAN_MEMLOCK_SIZE (64U*1024U*1024U) +@@ -56,8 +57,8 @@ int main(int argc, char *argv[]) { + + test_setup_logging(LOG_DEBUG); + +- if (is_run_on_travis_ci()) +- return log_tests_skipped("test-bpf fails on Travis CI: https://github.com/systemd/systemd/issues/9666"); ++ if (detect_container()) ++ return log_tests_skipped("test-bpf fails inside LXC and Docker containers: https://github.com/systemd/systemd/issues/9666"); + + assert_se(getrlimit(RLIMIT_MEMLOCK, &rl) >= 0); + rl.rlim_cur = rl.rlim_max = MAX3(rl.rlim_cur, rl.rlim_max, CAN_MEMLOCK_SIZE); diff --git a/debian/patches/tests-skip-test-bpf-only-when-we-re-100-sure-it-s-run-in-.patch b/debian/patches/tests-skip-test-bpf-only-when-we-re-100-sure-it-s-run-in-.patch new file mode 100644 index 0000000..c7a9bc8 --- /dev/null +++ b/debian/patches/tests-skip-test-bpf-only-when-we-re-100-sure-it-s-run-in-.patch @@ -0,0 +1,25 @@ +From: Evgeny Vereshchagin <evvers@ya.ru> +Date: Thu, 30 May 2019 03:29:50 +0200 +Subject: tests: skip test-bpf only when we're 100% sure it's run in + containers + +This is just a follow-up to https://github.com/systemd/systemd/pull/12617. + +(cherry picked from commit 6bd1457afe396864cc4b9884157a6126027ed85e) +--- + src/test/test-bpf.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/test/test-bpf.c b/src/test/test-bpf.c +index eb1d8d7..9252c60 100644 +--- a/src/test/test-bpf.c ++++ b/src/test/test-bpf.c +@@ -57,7 +57,7 @@ int main(int argc, char *argv[]) { + + test_setup_logging(LOG_DEBUG); + +- if (detect_container()) ++ if (detect_container() > 0) + return log_tests_skipped("test-bpf fails inside LXC and Docker containers: https://github.com/systemd/systemd/issues/9666"); + + assert_se(getrlimit(RLIMIT_MEMLOCK, &rl) >= 0); diff --git a/debian/patches/timedate-fix-emitted-value-when-ntp-client-is-enabled-dis.patch b/debian/patches/timedate-fix-emitted-value-when-ntp-client-is-enabled-dis.patch new file mode 100644 index 0000000..4ae8684 --- /dev/null +++ b/debian/patches/timedate-fix-emitted-value-when-ntp-client-is-enabled-dis.patch @@ -0,0 +1,31 @@ +From: Yu Watanabe <watanabe.yu+github@gmail.com> +Date: Mon, 11 Mar 2019 04:44:21 +0900 +Subject: timedate: fix emitted value when ntp client is enabled/disabled + (#11951) + +This fixes a regression originall caused by cf3872bd2 and +triggered by b4356b5720a. + +Fixes #11944 + +(cherry picked from commit 49942d6b1eac12f3157c628ee6249c3bbb3602aa) +--- + src/timedate/timedated.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c +index eeb17b6..324d4a4 100644 +--- a/src/timedate/timedated.c ++++ b/src/timedate/timedated.c +@@ -377,9 +377,9 @@ static int match_job_removed(sd_bus_message *m, void *userdata, sd_bus_error *er + n += !!u->path; + + if (n == 0) { +- (void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m), "/org/freedesktop/timedate1", "org.freedesktop.timedate1", "NTP", NULL); +- + c->slot_job_removed = sd_bus_slot_unref(c->slot_job_removed); ++ ++ (void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m), "/org/freedesktop/timedate1", "org.freedesktop.timedate1", "NTP", NULL); + } + + return 0; diff --git a/debian/patches/udev-network-drop-unused-parent_driver-argument-from-net_.patch b/debian/patches/udev-network-drop-unused-parent_driver-argument-from-net_.patch new file mode 100644 index 0000000..92a74a5 --- /dev/null +++ b/debian/patches/udev-network-drop-unused-parent_driver-argument-from-net_.patch @@ -0,0 +1,114 @@ +From: Yu Watanabe <watanabe.yu+github@gmail.com> +Date: Sun, 17 Feb 2019 00:47:45 +0900 +Subject: udev,network: drop unused parent_driver argument from + net_match_config() + +The argument has never been used. + +(cherry picked from commit 4f4daf418f2e750caae6bc26cd49daafc23ad4de) +--- + src/libsystemd-network/network-internal.c | 1 - + src/libsystemd-network/network-internal.h | 1 - + src/network/netdev/netdev.c | 2 +- + src/network/networkd-network.c | 9 ++------- + src/udev/net/link-config.c | 6 +----- + 5 files changed, 4 insertions(+), 15 deletions(-) + +diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c +index 0348e7f..34fac34 100644 +--- a/src/libsystemd-network/network-internal.c ++++ b/src/libsystemd-network/network-internal.c +@@ -102,7 +102,6 @@ bool net_match_config(Set *match_mac, + Condition *match_arch, + const struct ether_addr *dev_mac, + const char *dev_path, +- const char *dev_parent_driver, + const char *dev_driver, + const char *dev_type, + const char *dev_name) { +diff --git a/src/libsystemd-network/network-internal.h b/src/libsystemd-network/network-internal.h +index 0c8da84..944fd2c 100644 +--- a/src/libsystemd-network/network-internal.h ++++ b/src/libsystemd-network/network-internal.h +@@ -25,7 +25,6 @@ bool net_match_config(Set *match_mac, + Condition *match_arch, + const struct ether_addr *dev_mac, + const char *dev_path, +- const char *dev_parent_driver, + const char *dev_driver, + const char *dev_type, + const char *dev_name); +diff --git a/src/network/netdev/netdev.c b/src/network/netdev/netdev.c +index 0263917..ecd6cf4 100644 +--- a/src/network/netdev/netdev.c ++++ b/src/network/netdev/netdev.c +@@ -673,7 +673,7 @@ int netdev_load_one(Manager *manager, const char *filename) { + netdev_raw->match_host, netdev_raw->match_virt, + netdev_raw->match_kernel_cmdline, netdev_raw->match_kernel_version, + netdev_raw->match_arch, +- NULL, NULL, NULL, NULL, NULL, NULL) <= 0) ++ NULL, NULL, NULL, NULL, NULL) <= 0) + return 0; + + if (netdev_raw->kind == _NETDEV_KIND_INVALID) { +diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c +index 12344ec..9d08874 100644 +--- a/src/network/networkd-network.c ++++ b/src/network/networkd-network.c +@@ -424,8 +424,7 @@ int network_get_by_name(Manager *manager, const char *name, Network **ret) { + int network_get(Manager *manager, sd_device *device, + const char *ifname, const struct ether_addr *address, + Network **ret) { +- const char *path = NULL, *parent_driver = NULL, *driver = NULL, *devtype = NULL; +- sd_device *parent; ++ const char *path = NULL, *driver = NULL, *devtype = NULL; + Network *network; + + assert(manager); +@@ -434,9 +433,6 @@ int network_get(Manager *manager, sd_device *device, + if (device) { + (void) sd_device_get_property_value(device, "ID_PATH", &path); + +- if (sd_device_get_parent(device, &parent) >= 0) +- (void) sd_device_get_driver(parent, &parent_driver); +- + (void) sd_device_get_property_value(device, "ID_NET_DRIVER", &driver); + + (void) sd_device_get_devtype(device, &devtype); +@@ -448,8 +444,7 @@ int network_get(Manager *manager, sd_device *device, + network->match_name, network->match_host, + network->match_virt, network->match_kernel_cmdline, + network->match_kernel_version, network->match_arch, +- address, path, parent_driver, driver, +- devtype, ifname)) { ++ address, path, driver, devtype, ifname)) { + if (network->match_name && device) { + const char *attr; + uint8_t name_assign_type = NET_NAME_UNKNOWN; +diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c +index eb2477c..62830ae 100644 +--- a/src/udev/net/link-config.c ++++ b/src/udev/net/link-config.c +@@ -243,13 +243,10 @@ int link_config_get(link_config_ctx *ctx, sd_device *device, link_config **ret) + assert(ret); + + LIST_FOREACH(links, link, ctx->links) { +- const char *address = NULL, *id_path = NULL, *parent_driver = NULL, *id_net_driver = NULL, *devtype = NULL, *sysname = NULL; +- sd_device *parent; ++ const char *address = NULL, *id_path = NULL, *id_net_driver = NULL, *devtype = NULL, *sysname = NULL; + + (void) sd_device_get_sysattr_value(device, "address", &address); + (void) sd_device_get_property_value(device, "ID_PATH", &id_path); +- if (sd_device_get_parent(device, &parent) >= 0) +- (void) sd_device_get_driver(parent, &parent_driver); + (void) sd_device_get_property_value(device, "ID_NET_DRIVER", &id_net_driver); + (void) sd_device_get_devtype(device, &devtype); + (void) sd_device_get_sysname(device, &sysname); +@@ -260,7 +257,6 @@ int link_config_get(link_config_ctx *ctx, sd_device *device, link_config **ret) + link->match_kernel_version, link->match_arch, + address ? ether_aton(address) : NULL, + id_path, +- parent_driver, + id_net_driver, + devtype, + sysname)) { diff --git a/debian/patches/udev-restore-debug-level-when-logging-a-failure-in-the-ex.patch b/debian/patches/udev-restore-debug-level-when-logging-a-failure-in-the-ex.patch new file mode 100644 index 0000000..63cc83a --- /dev/null +++ b/debian/patches/udev-restore-debug-level-when-logging-a-failure-in-the-ex.patch @@ -0,0 +1,29 @@ +From: Franck Bui <fbui@suse.com> +Date: Tue, 5 Mar 2019 11:03:07 +0100 +Subject: udev: restore debug level when logging a failure in the external + prog called by IMPORT{program} + +It was already the case before commit a75211421fc9366068e6d9446e8e567246c72feb, +which upgraded the log to warning. + +This seems an unintended side effect as the commit message doesn't mention it +and the old behavior looks more appropriate. + +(cherry picked from commit 3c37dadf627677eef62fcfc0c0f07cc67c748a9e) +--- + src/udev/udev-rules.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c +index bc9c6c2..7fa4fd4 100644 +--- a/src/udev/udev-rules.c ++++ b/src/udev/udev-rules.c +@@ -647,7 +647,7 @@ static int import_program_into_properties(UdevEvent *event, + char *line; + int r; + +- r = udev_event_spawn(event, timeout_usec, false, program, result, sizeof result); ++ r = udev_event_spawn(event, timeout_usec, true, program, result, sizeof result); + if (r < 0) + return r; + if (r > 0) diff --git a/debian/patches/udev-run-programs-in-the-specified-order.patch b/debian/patches/udev-run-programs-in-the-specified-order.patch new file mode 100644 index 0000000..95c8f15 --- /dev/null +++ b/debian/patches/udev-run-programs-in-the-specified-order.patch @@ -0,0 +1,161 @@ +From: Yu Watanabe <watanabe.yu+github@gmail.com> +Date: Tue, 5 Mar 2019 04:01:34 +0900 +Subject: udev: run programs in the specified order + +This fixes bugs introduced by 29448498c724da7ade1b5efb20d7472c1b128d2c +and d838e14515c82b05a07f2bf393cce057b45b2b53. + +Previously, RUN and SECLABEL keys are stored in udev_list with its unique +flag is false. If the flag is false, then udev_list is just a linked +list and new entries are always added in the last. +So, we should use OrderedHashmap instead of Hashmap. + +Fixes #11368. + +(cherry picked from commit 39a15c8a8dad26deda140867f03e44a535b7bd8d) +--- + src/udev/udev-event.c | 6 +++--- + src/udev/udev-node.c | 6 +++--- + src/udev/udev-node.h | 2 +- + src/udev/udev-rules.c | 12 ++++++------ + src/udev/udev.h | 4 ++-- + src/udev/udevadm-test.c | 2 +- + 6 files changed, 16 insertions(+), 16 deletions(-) + +diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c +index 07b7365..faec4fc 100644 +--- a/src/udev/udev-event.c ++++ b/src/udev/udev-event.c +@@ -71,8 +71,8 @@ UdevEvent *udev_event_free(UdevEvent *event) { + sd_device_unref(event->dev); + sd_device_unref(event->dev_db_clone); + sd_netlink_unref(event->rtnl); +- hashmap_free_free_key(event->run_list); +- hashmap_free_free_free(event->seclabel_list); ++ ordered_hashmap_free_free_key(event->run_list); ++ ordered_hashmap_free_free_free(event->seclabel_list); + free(event->program_result); + free(event->name); + +@@ -873,7 +873,7 @@ void udev_event_execute_run(UdevEvent *event, usec_t timeout_usec) { + void *val; + Iterator i; + +- HASHMAP_FOREACH_KEY(val, cmd, event->run_list, i) { ++ ORDERED_HASHMAP_FOREACH_KEY(val, cmd, event->run_list, i) { + enum udev_builtin_cmd builtin_cmd = PTR_TO_INT(val); + char command[UTIL_PATH_SIZE]; + +diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c +index 1c00dd1..cfbbd7b 100644 +--- a/src/udev/udev-node.c ++++ b/src/udev/udev-node.c +@@ -272,7 +272,7 @@ int udev_node_update_old_links(sd_device *dev, sd_device *dev_old) { + + static int node_permissions_apply(sd_device *dev, bool apply, + mode_t mode, uid_t uid, gid_t gid, +- Hashmap *seclabel_list) { ++ OrderedHashmap *seclabel_list) { + const char *devnode, *subsystem, *id_filename = NULL; + struct stat stats; + dev_t devnum; +@@ -318,7 +318,7 @@ static int node_permissions_apply(sd_device *dev, bool apply, + log_device_debug(dev, "Preserve permissions of %s, %#o, uid=%u, gid=%u", devnode, mode, uid, gid); + + /* apply SECLABEL{$module}=$label */ +- HASHMAP_FOREACH_KEY(label, name, seclabel_list, i) { ++ ORDERED_HASHMAP_FOREACH_KEY(label, name, seclabel_list, i) { + int q; + + if (streq(name, "selinux")) { +@@ -386,7 +386,7 @@ static int xsprintf_dev_num_path_from_sd_device(sd_device *dev, char **ret) { + + int udev_node_add(sd_device *dev, bool apply, + mode_t mode, uid_t uid, gid_t gid, +- Hashmap *seclabel_list) { ++ OrderedHashmap *seclabel_list) { + const char *devnode, *devlink; + _cleanup_free_ char *filename = NULL; + int r; +diff --git a/src/udev/udev-node.h b/src/udev/udev-node.h +index 223c8f0..5ae816d 100644 +--- a/src/udev/udev-node.h ++++ b/src/udev/udev-node.h +@@ -10,6 +10,6 @@ + + int udev_node_add(sd_device *dev, bool apply, + mode_t mode, uid_t uid, gid_t gid, +- Hashmap *seclabel_list); ++ OrderedHashmap *seclabel_list); + int udev_node_remove(sd_device *dev); + int udev_node_update_old_links(sd_device *dev, sd_device *dev_old); +diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c +index 7fa4fd4..93709cc 100644 +--- a/src/udev/udev-rules.c ++++ b/src/udev/udev-rules.c +@@ -2291,13 +2291,13 @@ int udev_rules_apply_to_event( + return log_oom(); + + if (IN_SET(cur->key.op, OP_ASSIGN, OP_ASSIGN_FINAL)) +- hashmap_clear_free_free(event->seclabel_list); ++ ordered_hashmap_clear_free_free(event->seclabel_list); + +- r = hashmap_ensure_allocated(&event->seclabel_list, NULL); ++ r = ordered_hashmap_ensure_allocated(&event->seclabel_list, NULL); + if (r < 0) + return log_oom(); + +- r = hashmap_put(event->seclabel_list, name, label); ++ r = ordered_hashmap_put(event->seclabel_list, name, label); + if (r < 0) + return log_oom(); + log_device_debug(dev, "SECLABEL{%s}='%s' %s:%u", +@@ -2474,9 +2474,9 @@ int udev_rules_apply_to_event( + _cleanup_free_ char *cmd = NULL; + + if (IN_SET(cur->key.op, OP_ASSIGN, OP_ASSIGN_FINAL)) +- hashmap_clear_free_key(event->run_list); ++ ordered_hashmap_clear_free_key(event->run_list); + +- r = hashmap_ensure_allocated(&event->run_list, NULL); ++ r = ordered_hashmap_ensure_allocated(&event->run_list, NULL); + if (r < 0) + return log_oom(); + +@@ -2484,7 +2484,7 @@ int udev_rules_apply_to_event( + if (!cmd) + return log_oom(); + +- r = hashmap_put(event->run_list, cmd, INT_TO_PTR(cur->key.builtin_cmd)); ++ r = ordered_hashmap_put(event->run_list, cmd, INT_TO_PTR(cur->key.builtin_cmd)); + if (r < 0) + return log_oom(); + +diff --git a/src/udev/udev.h b/src/udev/udev.h +index 3bc69ff..2fb49dc 100644 +--- a/src/udev/udev.h ++++ b/src/udev/udev.h +@@ -25,8 +25,8 @@ typedef struct UdevEvent { + mode_t mode; + uid_t uid; + gid_t gid; +- Hashmap *seclabel_list; +- Hashmap *run_list; ++ OrderedHashmap *seclabel_list; ++ OrderedHashmap *run_list; + usec_t exec_delay_usec; + usec_t birth_usec; + sd_netlink *rtnl; +diff --git a/src/udev/udevadm-test.c b/src/udev/udevadm-test.c +index 54c525e..9c17844 100644 +--- a/src/udev/udevadm-test.c ++++ b/src/udev/udevadm-test.c +@@ -135,7 +135,7 @@ int test_main(int argc, char *argv[], void *userdata) { + FOREACH_DEVICE_PROPERTY(dev, key, value) + printf("%s=%s\n", key, value); + +- HASHMAP_FOREACH_KEY(val, cmd, event->run_list, i) { ++ ORDERED_HASHMAP_FOREACH_KEY(val, cmd, event->run_list, i) { + char program[UTIL_PATH_SIZE]; + + udev_event_apply_format(event, cmd, program, sizeof(program), false); |