diff options
Diffstat (limited to 'meta/recipes-core/systemd/systemd')
21 files changed, 2455 insertions, 0 deletions
diff --git a/meta/recipes-core/systemd/systemd/00-create-volatile.conf b/meta/recipes-core/systemd/systemd/00-create-volatile.conf index 87cbe1e7d3..c4277221a2 100644 --- a/meta/recipes-core/systemd/systemd/00-create-volatile.conf +++ b/meta/recipes-core/systemd/systemd/00-create-volatile.conf | |||
@@ -3,5 +3,6 @@ | |||
3 | # inside /var/log. | 3 | # inside /var/log. |
4 | 4 | ||
5 | 5 | ||
6 | d /run/lock 1777 - - - | ||
6 | d /var/volatile/log - - - - | 7 | d /var/volatile/log - - - - |
7 | d /var/volatile/tmp 1777 - - | 8 | d /var/volatile/tmp 1777 - - |
diff --git a/meta/recipes-core/systemd/systemd/CVE-2018-21029.patch b/meta/recipes-core/systemd/systemd/CVE-2018-21029.patch new file mode 100644 index 0000000000..8d3801a248 --- /dev/null +++ b/meta/recipes-core/systemd/systemd/CVE-2018-21029.patch | |||
@@ -0,0 +1,120 @@ | |||
1 | From 3f9d9289ee8730a81a0464539f4e1ba2d23d0ce9 Mon Sep 17 00:00:00 2001 | ||
2 | From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= <joerg@thalheim.io> | ||
3 | Date: Tue, 3 Mar 2020 23:31:25 +0000 | ||
4 | Subject: [PATCH] systemd-resolved: use hostname for certificate validation in | ||
5 | DoT | ||
6 | |||
7 | Widely accepted certificates for IP addresses are expensive and only | ||
8 | affordable for larger organizations. Therefore if the user provides | ||
9 | the hostname in the DNS= option, we should use it instead of the IP | ||
10 | address. | ||
11 | |||
12 | (cherry picked from commit eec394f10bbfcc3d2fc8504ad8ff5be44231abd5) | ||
13 | |||
14 | CVE: CVE-2018-21029 | ||
15 | Upstream-Status: Backport [ff26d281aec0877b43269f18c6282cd79a7f5529] | ||
16 | Signed-off-by: Marek Vasut <marex@denx.de> | ||
17 | --- | ||
18 | man/resolved.conf.xml | 16 +++++++++++----- | ||
19 | src/resolve/resolved-dnstls-gnutls.c | 20 ++++++++++++-------- | ||
20 | src/resolve/resolved-dnstls-openssl.c | 15 +++++++++++---- | ||
21 | 3 files changed, 34 insertions(+), 17 deletions(-) | ||
22 | |||
23 | diff --git a/man/resolved.conf.xml b/man/resolved.conf.xml | ||
24 | index 818000145b..37161ebcbc 100644 | ||
25 | --- a/man/resolved.conf.xml | ||
26 | +++ b/man/resolved.conf.xml | ||
27 | @@ -193,11 +193,17 @@ | ||
28 | <varlistentry> | ||
29 | <term><varname>DNSOverTLS=</varname></term> | ||
30 | <listitem> | ||
31 | - <para>Takes a boolean argument or <literal>opportunistic</literal>. | ||
32 | - If true all connections to the server will be encrypted. Note that | ||
33 | - this mode requires a DNS server that supports DNS-over-TLS and has | ||
34 | - a valid certificate for it's IP. If the DNS server does not support | ||
35 | - DNS-over-TLS all DNS requests will fail. When set to <literal>opportunistic</literal> | ||
36 | + <para>Takes a boolean argument or <literal>opportunistic</literal>. If | ||
37 | + true all connections to the server will be encrypted. Note that this | ||
38 | + mode requires a DNS server that supports DNS-over-TLS and has a valid | ||
39 | + certificate. If the hostname was specified in <varname>DNS=</varname> | ||
40 | + by using the format format <literal>address#server_name</literal> it | ||
41 | + is used to validate its certificate and also to enable Server Name | ||
42 | + Indication (SNI) when opening a TLS connection. Otherwise | ||
43 | + the certificate is checked against the server's IP. | ||
44 | + If the DNS server does not support DNS-over-TLS all DNS requests will fail.</para> | ||
45 | + | ||
46 | + <para>When set to <literal>opportunistic</literal> | ||
47 | DNS request are attempted to send encrypted with DNS-over-TLS. | ||
48 | If the DNS server does not support TLS, DNS-over-TLS is disabled. | ||
49 | Note that this mode makes DNS-over-TLS vulnerable to "downgrade" | ||
50 | diff --git a/src/resolve/resolved-dnstls-gnutls.c b/src/resolve/resolved-dnstls-gnutls.c | ||
51 | index ed0a31e8bf..c7215723a7 100644 | ||
52 | --- a/src/resolve/resolved-dnstls-gnutls.c | ||
53 | +++ b/src/resolve/resolved-dnstls-gnutls.c | ||
54 | @@ -56,15 +56,19 @@ int dnstls_stream_connect_tls(DnsStream *stream, DnsServer *server) { | ||
55 | } | ||
56 | |||
57 | if (server->manager->dns_over_tls_mode == DNS_OVER_TLS_YES) { | ||
58 | - stream->dnstls_data.validation.type = GNUTLS_DT_IP_ADDRESS; | ||
59 | - if (server->family == AF_INET) { | ||
60 | - stream->dnstls_data.validation.data = (unsigned char*) &server->address.in.s_addr; | ||
61 | - stream->dnstls_data.validation.size = 4; | ||
62 | - } else { | ||
63 | - stream->dnstls_data.validation.data = server->address.in6.s6_addr; | ||
64 | - stream->dnstls_data.validation.size = 16; | ||
65 | + if (server->server_name) | ||
66 | + gnutls_session_set_verify_cert(gs, server->server_name, 0); | ||
67 | + else { | ||
68 | + stream->dnstls_data.validation.type = GNUTLS_DT_IP_ADDRESS; | ||
69 | + if (server->family == AF_INET) { | ||
70 | + stream->dnstls_data.validation.data = (unsigned char*) &server->address.in.s_addr; | ||
71 | + stream->dnstls_data.validation.size = 4; | ||
72 | + } else { | ||
73 | + stream->dnstls_data.validation.data = server->address.in6.s6_addr; | ||
74 | + stream->dnstls_data.validation.size = 16; | ||
75 | + } | ||
76 | + gnutls_session_set_verify_cert2(gs, &stream->dnstls_data.validation, 1, 0); | ||
77 | } | ||
78 | - gnutls_session_set_verify_cert2(gs, &stream->dnstls_data.validation, 1, 0); | ||
79 | } | ||
80 | |||
81 | gnutls_handshake_set_timeout(gs, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT); | ||
82 | diff --git a/src/resolve/resolved-dnstls-openssl.c b/src/resolve/resolved-dnstls-openssl.c | ||
83 | index 85e202ff74..007aedaa5b 100644 | ||
84 | --- a/src/resolve/resolved-dnstls-openssl.c | ||
85 | +++ b/src/resolve/resolved-dnstls-openssl.c | ||
86 | @@ -6,6 +6,7 @@ | ||
87 | |||
88 | #include <openssl/bio.h> | ||
89 | #include <openssl/err.h> | ||
90 | +#include <openssl/x509v3.h> | ||
91 | |||
92 | #include "io-util.h" | ||
93 | #include "resolved-dns-stream.h" | ||
94 | @@ -78,13 +79,19 @@ int dnstls_stream_connect_tls(DnsStream *stream, DnsServer *server) { | ||
95 | |||
96 | if (server->manager->dns_over_tls_mode == DNS_OVER_TLS_YES) { | ||
97 | X509_VERIFY_PARAM *v; | ||
98 | - const unsigned char *ip; | ||
99 | |||
100 | SSL_set_verify(s, SSL_VERIFY_PEER, NULL); | ||
101 | v = SSL_get0_param(s); | ||
102 | - ip = server->family == AF_INET ? (const unsigned char*) &server->address.in.s_addr : server->address.in6.s6_addr; | ||
103 | - if (!X509_VERIFY_PARAM_set1_ip(v, ip, FAMILY_ADDRESS_SIZE(server->family))) | ||
104 | - return -ECONNREFUSED; | ||
105 | + if (server->server_name) { | ||
106 | + X509_VERIFY_PARAM_set_hostflags(v, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS); | ||
107 | + if (X509_VERIFY_PARAM_set1_host(v, server->server_name, 0) == 0) | ||
108 | + return -ECONNREFUSED; | ||
109 | + } else { | ||
110 | + const unsigned char *ip; | ||
111 | + ip = server->family == AF_INET ? (const unsigned char*) &server->address.in.s_addr : server->address.in6.s6_addr; | ||
112 | + if (X509_VERIFY_PARAM_set1_ip(v, ip, FAMILY_ADDRESS_SIZE(server->family)) == 0) | ||
113 | + return -ECONNREFUSED; | ||
114 | + } | ||
115 | } | ||
116 | |||
117 | ERR_clear_error(); | ||
118 | -- | ||
119 | 2.40.1 | ||
120 | |||
diff --git a/meta/recipes-core/systemd/systemd/CVE-2020-13529.patch b/meta/recipes-core/systemd/systemd/CVE-2020-13529.patch new file mode 100644 index 0000000000..6b499efbd8 --- /dev/null +++ b/meta/recipes-core/systemd/systemd/CVE-2020-13529.patch | |||
@@ -0,0 +1,42 @@ | |||
1 | From 38e980a6a5a3442c2f48b1f827284388096d8ca5 Mon Sep 17 00:00:00 2001 | ||
2 | From: Yu Watanabe <watanabe.yu+github@gmail.com> | ||
3 | Date: Thu, 24 Jun 2021 01:22:07 +0900 | ||
4 | Subject: [PATCH] sd-dhcp-client: tentatively ignore FORCERENEW command | ||
5 | |||
6 | This makes DHCP client ignore FORCERENEW requests, as unauthenticated | ||
7 | FORCERENEW requests causes a security issue (TALOS-2020-1142, CVE-2020-13529). | ||
8 | |||
9 | Let's re-enable this after RFC3118 (Authentication for DHCP Messages) | ||
10 | and/or RFC6704 (Forcerenew Nonce Authentication) are implemented. | ||
11 | |||
12 | Fixes #16774. | ||
13 | |||
14 | Upstream-Status: Backport [https://github.com/systemd/systemd/commit/38e980a6a5a3442c2f48b1f827284388096d8ca5] | ||
15 | CVE: CVE-2020-13529 | ||
16 | |||
17 | Signed-off-by: Ranjitsinh Rathod <ranjitsinh.rathod@kpit.com> | ||
18 | |||
19 | --- | ||
20 | src/libsystemd-network/sd-dhcp-client.c | 8 ++++++++ | ||
21 | 1 file changed, 8 insertions(+) | ||
22 | |||
23 | --- a/src/libsystemd-network/sd-dhcp-client.c | ||
24 | +++ b/src/libsystemd-network/sd-dhcp-client.c | ||
25 | @@ -1392,9 +1392,17 @@ static int client_handle_forcerenew(sd_dhcp_client *client, DHCPMessage *force, | ||
26 | if (r != DHCP_FORCERENEW) | ||
27 | return -ENOMSG; | ||
28 | |||
29 | +#if 0 | ||
30 | log_dhcp_client(client, "FORCERENEW"); | ||
31 | |||
32 | return 0; | ||
33 | +#else | ||
34 | + /* FIXME: Ignore FORCERENEW requests until we implement RFC3118 (Authentication for DHCP | ||
35 | + * Messages) and/or RFC6704 (Forcerenew Nonce Authentication), as unauthenticated FORCERENEW | ||
36 | + * requests causes a security issue (TALOS-2020-1142, CVE-2020-13529). */ | ||
37 | + log_dhcp_client(client, "Received FORCERENEW, ignoring."); | ||
38 | + return -ENOMSG; | ||
39 | +#endif | ||
40 | } | ||
41 | |||
42 | static bool lease_equal(const sd_dhcp_lease *a, const sd_dhcp_lease *b) { | ||
diff --git a/meta/recipes-core/systemd/systemd/CVE-2021-33910.patch b/meta/recipes-core/systemd/systemd/CVE-2021-33910.patch new file mode 100644 index 0000000000..e92d721d3d --- /dev/null +++ b/meta/recipes-core/systemd/systemd/CVE-2021-33910.patch | |||
@@ -0,0 +1,67 @@ | |||
1 | Backport of: | ||
2 | |||
3 | From 441e0115646d54f080e5c3bb0ba477c892861ab9 Mon Sep 17 00:00:00 2001 | ||
4 | From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl> | ||
5 | Date: Wed, 23 Jun 2021 11:46:41 +0200 | ||
6 | Subject: [PATCH 1/2] basic/unit-name: do not use strdupa() on a path | ||
7 | |||
8 | The path may have unbounded length, for example through a fuse mount. | ||
9 | |||
10 | CVE-2021-33910: attacked controlled alloca() leads to crash in systemd and | ||
11 | ultimately a kernel panic. Systemd parses the content of /proc/self/mountinfo | ||
12 | and each mountpoint is passed to mount_setup_unit(), which calls | ||
13 | unit_name_path_escape() underneath. A local attacker who is able to mount a | ||
14 | filesystem with a very long path can crash systemd and the whole system. | ||
15 | |||
16 | https://bugzilla.redhat.com/show_bug.cgi?id=1970887 | ||
17 | |||
18 | The resulting string length is bounded by UNIT_NAME_MAX, which is 256. But we | ||
19 | can't easily check the length after simplification before doing the | ||
20 | simplification, which in turns uses a copy of the string we can write to. | ||
21 | So we can't reject paths that are too long before doing the duplication. | ||
22 | Hence the most obvious solution is to switch back to strdup(), as before | ||
23 | 7410616cd9dbbec97cf98d75324da5cda2b2f7a2. | ||
24 | |||
25 | Upstream-Status: Backport [https://github.com/systemd/systemd/pull/20256/commits/441e0115646d54f080e5c3bb0ba477c892861ab9] | ||
26 | CVE: CVE-2021-33910 | ||
27 | |||
28 | Signed-off-by: Ranjitsinh Rathod <ranjitsinh.rathod@kpit.com> | ||
29 | |||
30 | --- | ||
31 | src/basic/unit-name.c | 13 +++++-------- | ||
32 | 1 file changed, 5 insertions(+), 8 deletions(-) | ||
33 | |||
34 | --- a/src/basic/unit-name.c | ||
35 | +++ b/src/basic/unit-name.c | ||
36 | @@ -369,12 +369,13 @@ int unit_name_unescape(const char *f, char **ret) { | ||
37 | } | ||
38 | |||
39 | int unit_name_path_escape(const char *f, char **ret) { | ||
40 | - char *p, *s; | ||
41 | + _cleanup_free_ char *p = NULL; | ||
42 | + char *s; | ||
43 | |||
44 | assert(f); | ||
45 | assert(ret); | ||
46 | |||
47 | - p = strdupa(f); | ||
48 | + p = strdup(f); | ||
49 | if (!p) | ||
50 | return -ENOMEM; | ||
51 | |||
52 | @@ -386,13 +387,9 @@ int unit_name_path_escape(const char *f, char **ret) { | ||
53 | if (!path_is_normalized(p)) | ||
54 | return -EINVAL; | ||
55 | |||
56 | - /* Truncate trailing slashes */ | ||
57 | + /* Truncate trailing slashes and skip leading slashes */ | ||
58 | delete_trailing_chars(p, "/"); | ||
59 | - | ||
60 | - /* Truncate leading slashes */ | ||
61 | - p = skip_leading_chars(p, "/"); | ||
62 | - | ||
63 | - s = unit_name_escape(p); | ||
64 | + s = unit_name_escape(skip_leading_chars(p, "/")); | ||
65 | } | ||
66 | if (!s) | ||
67 | return -ENOMEM; | ||
diff --git a/meta/recipes-core/systemd/systemd/CVE-2021-3997-1.patch b/meta/recipes-core/systemd/systemd/CVE-2021-3997-1.patch new file mode 100644 index 0000000000..341976822b --- /dev/null +++ b/meta/recipes-core/systemd/systemd/CVE-2021-3997-1.patch | |||
@@ -0,0 +1,65 @@ | |||
1 | Backport of the following upstream commit: | ||
2 | From fbb77e1e55866633c9f064e2b3bcf2b6402d962d Mon Sep 17 00:00:00 2001 | ||
3 | From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl> | ||
4 | Date: Tue, 23 Nov 2021 15:55:45 +0100 | ||
5 | Subject: [PATCH 1/3] shared/rm_rf: refactor rm_rf_children_inner() to shorten | ||
6 | code a bit | ||
7 | |||
8 | CVE: CVE-2021-3997 | ||
9 | Upstream-Status: Backport [http://archive.ubuntu.com/ubuntu/pool/main/s/systemd/systemd_245.4-4ubuntu3.15.debian.tar.xz] | ||
10 | Signed-off-by: Purushottam Choudhary <Purushottam.Choudhary@kpit.com> | ||
11 | --- | ||
12 | src/basic/rm-rf.c | 27 +++++++++------------------ | ||
13 | 1 file changed, 9 insertions(+), 18 deletions(-) | ||
14 | |||
15 | --- a/src/basic/rm-rf.c | ||
16 | +++ b/src/basic/rm-rf.c | ||
17 | @@ -34,7 +34,7 @@ | ||
18 | const struct stat *root_dev) { | ||
19 | |||
20 | struct stat st; | ||
21 | - int r; | ||
22 | + int r, q = 0; | ||
23 | |||
24 | assert(fd >= 0); | ||
25 | assert(fname); | ||
26 | @@ -50,7 +50,6 @@ | ||
27 | |||
28 | if (is_dir) { | ||
29 | _cleanup_close_ int subdir_fd = -1; | ||
30 | - int q; | ||
31 | |||
32 | /* if root_dev is set, remove subdirectories only if device is same */ | ||
33 | if (root_dev && st.st_dev != root_dev->st_dev) | ||
34 | @@ -86,23 +85,15 @@ | ||
35 | * again for each directory */ | ||
36 | q = rm_rf_children(TAKE_FD(subdir_fd), flags | REMOVE_PHYSICAL, root_dev); | ||
37 | |||
38 | - r = unlinkat(fd, fname, AT_REMOVEDIR); | ||
39 | - if (r < 0) | ||
40 | - return r; | ||
41 | - if (q < 0) | ||
42 | - return q; | ||
43 | - | ||
44 | - return 1; | ||
45 | - | ||
46 | - } else if (!(flags & REMOVE_ONLY_DIRECTORIES)) { | ||
47 | - r = unlinkat(fd, fname, 0); | ||
48 | - if (r < 0) | ||
49 | - return r; | ||
50 | - | ||
51 | - return 1; | ||
52 | - } | ||
53 | + } else if (flags & REMOVE_ONLY_DIRECTORIES) | ||
54 | + return 0; | ||
55 | |||
56 | - return 0; | ||
57 | + r = unlinkat(fd, fname, is_dir ? AT_REMOVEDIR : 0); | ||
58 | + if (r < 0) | ||
59 | + return r; | ||
60 | + if (q < 0) | ||
61 | + return q; | ||
62 | + return 1; | ||
63 | } | ||
64 | |||
65 | int rm_rf_children( | ||
diff --git a/meta/recipes-core/systemd/systemd/CVE-2021-3997-2.patch b/meta/recipes-core/systemd/systemd/CVE-2021-3997-2.patch new file mode 100644 index 0000000000..066e10fbbc --- /dev/null +++ b/meta/recipes-core/systemd/systemd/CVE-2021-3997-2.patch | |||
@@ -0,0 +1,101 @@ | |||
1 | Backport of the following upstream commit: | ||
2 | From bd0127daaaae009ade053718f7d2f297aee4acaf Mon Sep 17 00:00:00 2001 | ||
3 | From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl> | ||
4 | Date: Tue, 23 Nov 2021 16:56:42 +0100 | ||
5 | Subject: [PATCH 2/3] shared/rm_rf: refactor rm_rf() to shorten code a bit | ||
6 | |||
7 | CVE: CVE-2021-3997 | ||
8 | Upstream-Status: Backport [http://archive.ubuntu.com/ubuntu/pool/main/s/systemd/systemd_245.4-4ubuntu3.15.debian.tar.xz] | ||
9 | Signed-off-by: Purushottam Choudhary <Purushottam.Choudhary@kpit.com> | ||
10 | --- | ||
11 | src/basic/rm-rf.c | 53 ++++++++++++++++++++-------------------------- | ||
12 | 1 file changed, 23 insertions(+), 30 deletions(-) | ||
13 | |||
14 | --- a/src/basic/rm-rf.c | ||
15 | +++ b/src/basic/rm-rf.c | ||
16 | @@ -159,7 +159,7 @@ | ||
17 | } | ||
18 | |||
19 | int rm_rf(const char *path, RemoveFlags flags) { | ||
20 | - int fd, r; | ||
21 | + int fd, r, q = 0; | ||
22 | |||
23 | assert(path); | ||
24 | |||
25 | @@ -191,49 +191,47 @@ | ||
26 | } | ||
27 | |||
28 | fd = open(path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME); | ||
29 | - if (fd < 0) { | ||
30 | + if (fd >= 0) { | ||
31 | + /* We have a dir */ | ||
32 | + r = rm_rf_children(fd, flags, NULL); | ||
33 | + | ||
34 | + if (FLAGS_SET(flags, REMOVE_ROOT)) { | ||
35 | + q = rmdir(path); | ||
36 | + if (q < 0) | ||
37 | + q = -errno; | ||
38 | + } | ||
39 | + } else { | ||
40 | if (FLAGS_SET(flags, REMOVE_MISSING_OK) && errno == ENOENT) | ||
41 | return 0; | ||
42 | |||
43 | if (!IN_SET(errno, ENOTDIR, ELOOP)) | ||
44 | return -errno; | ||
45 | |||
46 | - if (FLAGS_SET(flags, REMOVE_ONLY_DIRECTORIES)) | ||
47 | + if (FLAGS_SET(flags, REMOVE_ONLY_DIRECTORIES) || !FLAGS_SET(flags, REMOVE_ROOT)) | ||
48 | return 0; | ||
49 | |||
50 | - if (FLAGS_SET(flags, REMOVE_ROOT)) { | ||
51 | - | ||
52 | - if (!FLAGS_SET(flags, REMOVE_PHYSICAL)) { | ||
53 | - struct statfs s; | ||
54 | - | ||
55 | - if (statfs(path, &s) < 0) | ||
56 | - return -errno; | ||
57 | - if (is_physical_fs(&s)) | ||
58 | - return log_error_errno(SYNTHETIC_ERRNO(EPERM), | ||
59 | - "Attempted to remove files from a disk file system under \"%s\", refusing.", | ||
60 | - path); | ||
61 | - } | ||
62 | - | ||
63 | - if (unlink(path) < 0) { | ||
64 | - if (FLAGS_SET(flags, REMOVE_MISSING_OK) && errno == ENOENT) | ||
65 | - return 0; | ||
66 | + if (!FLAGS_SET(flags, REMOVE_PHYSICAL)) { | ||
67 | + struct statfs s; | ||
68 | |||
69 | + if (statfs(path, &s) < 0) | ||
70 | return -errno; | ||
71 | - } | ||
72 | + if (is_physical_fs(&s)) | ||
73 | + return log_error_errno(SYNTHETIC_ERRNO(EPERM), | ||
74 | + "Attempted to remove files from a disk file system under \"%s\", refusing.", | ||
75 | + path); | ||
76 | } | ||
77 | |||
78 | - return 0; | ||
79 | + r = 0; | ||
80 | + q = unlink(path); | ||
81 | + if (q < 0) | ||
82 | + q = -errno; | ||
83 | } | ||
84 | |||
85 | - r = rm_rf_children(fd, flags, NULL); | ||
86 | - | ||
87 | - if (FLAGS_SET(flags, REMOVE_ROOT) && | ||
88 | - rmdir(path) < 0 && | ||
89 | - r >= 0 && | ||
90 | - (!FLAGS_SET(flags, REMOVE_MISSING_OK) || errno != ENOENT)) | ||
91 | - r = -errno; | ||
92 | - | ||
93 | - return r; | ||
94 | + if (r < 0) | ||
95 | + return r; | ||
96 | + if (q < 0 && (q != -ENOENT || !FLAGS_SET(flags, REMOVE_MISSING_OK))) | ||
97 | + return q; | ||
98 | + return 0; | ||
99 | } | ||
100 | |||
101 | int rm_rf_child(int fd, const char *name, RemoveFlags flags) { | ||
diff --git a/meta/recipes-core/systemd/systemd/CVE-2021-3997-3.patch b/meta/recipes-core/systemd/systemd/CVE-2021-3997-3.patch new file mode 100644 index 0000000000..c96b8d9a6e --- /dev/null +++ b/meta/recipes-core/systemd/systemd/CVE-2021-3997-3.patch | |||
@@ -0,0 +1,266 @@ | |||
1 | Backport of the following upstream commit: | ||
2 | From bef8e8e577368697b2e6f85183b1dbc99e0e520f Mon Sep 17 00:00:00 2001 | ||
3 | From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl> | ||
4 | Date: Tue, 30 Nov 2021 22:29:05 +0100 | ||
5 | Subject: [PATCH 3/3] shared/rm-rf: loop over nested directories instead of | ||
6 | instead of recursing | ||
7 | |||
8 | To remove directory structures, we need to remove the innermost items first, | ||
9 | and then recursively remove higher-level directories. We would recursively | ||
10 | descend into directories and invoke rm_rf_children and rm_rm_children_inner. | ||
11 | This is problematic when too many directories are nested. | ||
12 | |||
13 | Instead, let's create a "TODO" queue. In the the queue, for each level we | ||
14 | hold the DIR* object we were working on, and the name of the directory. This | ||
15 | allows us to leave a partially-processed directory, and restart the removal | ||
16 | loop one level down. When done with the inner directory, we use the name to | ||
17 | unlinkat() it from the parent, and proceed with the removal of other items. | ||
18 | |||
19 | Because the nesting is increased by one level, it is best to view this patch | ||
20 | with -b/--ignore-space-change. | ||
21 | |||
22 | This fixes CVE-2021-3997, https://bugzilla.redhat.com/show_bug.cgi?id=2024639. | ||
23 | The issue was reported and patches reviewed by Qualys Team. | ||
24 | Mauro Matteo Cascella and Riccardo Schirone from Red Hat handled the disclosure. | ||
25 | |||
26 | CVE: CVE-2021-3997 | ||
27 | Upstream-Status: Backport [http://archive.ubuntu.com/ubuntu/pool/main/s/systemd/systemd_245.4-4ubuntu3.15.debian.tar.xz] | ||
28 | Signed-off-by: Purushottam Choudhary <Purushottam.Choudhary@kpit.com> | ||
29 | --- | ||
30 | src/basic/rm-rf.c | 161 +++++++++++++++++++++++++++++++-------------- | ||
31 | 1 file changed, 113 insertions(+), 48 deletions(-) | ||
32 | |||
33 | --- a/src/basic/rm-rf.c | ||
34 | +++ b/src/basic/rm-rf.c | ||
35 | @@ -26,12 +26,13 @@ | ||
36 | return !is_temporary_fs(sfs) && !is_cgroup_fs(sfs); | ||
37 | } | ||
38 | |||
39 | -static int rm_rf_children_inner( | ||
40 | +static int rm_rf_inner_child( | ||
41 | int fd, | ||
42 | const char *fname, | ||
43 | int is_dir, | ||
44 | RemoveFlags flags, | ||
45 | - const struct stat *root_dev) { | ||
46 | + const struct stat *root_dev, | ||
47 | + bool allow_recursion) { | ||
48 | |||
49 | struct stat st; | ||
50 | int r, q = 0; | ||
51 | @@ -49,9 +50,7 @@ | ||
52 | } | ||
53 | |||
54 | if (is_dir) { | ||
55 | - _cleanup_close_ int subdir_fd = -1; | ||
56 | - | ||
57 | - /* if root_dev is set, remove subdirectories only if device is same */ | ||
58 | + /* If root_dev is set, remove subdirectories only if device is same */ | ||
59 | if (root_dev && st.st_dev != root_dev->st_dev) | ||
60 | return 0; | ||
61 | |||
62 | @@ -63,7 +62,6 @@ | ||
63 | return 0; | ||
64 | |||
65 | if ((flags & REMOVE_SUBVOLUME) && st.st_ino == 256) { | ||
66 | - | ||
67 | /* This could be a subvolume, try to remove it */ | ||
68 | |||
69 | r = btrfs_subvol_remove_fd(fd, fname, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA); | ||
70 | @@ -77,13 +75,16 @@ | ||
71 | return 1; | ||
72 | } | ||
73 | |||
74 | - subdir_fd = openat(fd, fname, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME); | ||
75 | + if (!allow_recursion) | ||
76 | + return -EISDIR; | ||
77 | + | ||
78 | + int subdir_fd = openat(fd, fname, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME); | ||
79 | if (subdir_fd < 0) | ||
80 | return -errno; | ||
81 | |||
82 | /* We pass REMOVE_PHYSICAL here, to avoid doing the fstatfs() to check the file system type | ||
83 | * again for each directory */ | ||
84 | - q = rm_rf_children(TAKE_FD(subdir_fd), flags | REMOVE_PHYSICAL, root_dev); | ||
85 | + q = rm_rf_children(subdir_fd, flags | REMOVE_PHYSICAL, root_dev); | ||
86 | |||
87 | } else if (flags & REMOVE_ONLY_DIRECTORIES) | ||
88 | return 0; | ||
89 | @@ -96,64 +97,128 @@ | ||
90 | return 1; | ||
91 | } | ||
92 | |||
93 | +typedef struct TodoEntry { | ||
94 | + DIR *dir; /* A directory that we were operating on. */ | ||
95 | + char *dirname; /* The filename of that directory itself. */ | ||
96 | +} TodoEntry; | ||
97 | + | ||
98 | +static void free_todo_entries(TodoEntry **todos) { | ||
99 | + for (TodoEntry *x = *todos; x && x->dir; x++) { | ||
100 | + closedir(x->dir); | ||
101 | + free(x->dirname); | ||
102 | + } | ||
103 | + | ||
104 | + freep(todos); | ||
105 | +} | ||
106 | + | ||
107 | int rm_rf_children( | ||
108 | int fd, | ||
109 | RemoveFlags flags, | ||
110 | const struct stat *root_dev) { | ||
111 | |||
112 | - _cleanup_closedir_ DIR *d = NULL; | ||
113 | - struct dirent *de; | ||
114 | + _cleanup_(free_todo_entries) TodoEntry *todos = NULL; | ||
115 | + size_t n_todo = 0, allocated = 0; | ||
116 | + _cleanup_free_ char *dirname = NULL; /* Set when we are recursing and want to delete ourselves */ | ||
117 | int ret = 0, r; | ||
118 | |||
119 | - assert(fd >= 0); | ||
120 | + /* Return the first error we run into, but nevertheless try to go on. | ||
121 | + * The passed fd is closed in all cases, including on failure. */ | ||
122 | |||
123 | - /* This returns the first error we run into, but nevertheless tries to go on. This closes the passed | ||
124 | - * fd, in all cases, including on failure. */ | ||
125 | + for (;;) { /* This loop corresponds to the directory nesting level. */ | ||
126 | + _cleanup_closedir_ DIR *d = NULL; | ||
127 | + struct dirent *de; | ||
128 | + | ||
129 | + if (n_todo > 0) { | ||
130 | + /* We know that we are in recursion here, because n_todo is set. | ||
131 | + * We need to remove the inner directory we were operating on. */ | ||
132 | + assert(dirname); | ||
133 | + r = unlinkat(dirfd(todos[n_todo-1].dir), dirname, AT_REMOVEDIR); | ||
134 | + if (r < 0 && r != -ENOENT && ret == 0) | ||
135 | + ret = r; | ||
136 | + dirname = mfree(dirname); | ||
137 | + | ||
138 | + /* And now let's back out one level up */ | ||
139 | + n_todo --; | ||
140 | + d = TAKE_PTR(todos[n_todo].dir); | ||
141 | + dirname = TAKE_PTR(todos[n_todo].dirname); | ||
142 | + | ||
143 | + assert(d); | ||
144 | + fd = dirfd(d); /* Retrieve the file descriptor from the DIR object */ | ||
145 | + assert(fd >= 0); | ||
146 | + } else { | ||
147 | + next_fd: | ||
148 | + assert(fd >= 0); | ||
149 | + d = fdopendir(fd); | ||
150 | + if (!d) { | ||
151 | + safe_close(fd); | ||
152 | + return -errno; | ||
153 | + } | ||
154 | + fd = dirfd(d); /* We donated the fd to fdopendir(). Let's make sure we sure we have | ||
155 | + * the right descriptor even if it were to internally invalidate the | ||
156 | + * one we passed. */ | ||
157 | + | ||
158 | + if (!(flags & REMOVE_PHYSICAL)) { | ||
159 | + struct statfs sfs; | ||
160 | + | ||
161 | + if (fstatfs(fd, &sfs) < 0) | ||
162 | + return -errno; | ||
163 | + | ||
164 | + if (is_physical_fs(&sfs)) { | ||
165 | + /* We refuse to clean physical file systems with this call, unless | ||
166 | + * explicitly requested. This is extra paranoia just to be sure we | ||
167 | + * never ever remove non-state data. */ | ||
168 | + | ||
169 | + _cleanup_free_ char *path = NULL; | ||
170 | + | ||
171 | + (void) fd_get_path(fd, &path); | ||
172 | + return log_error_errno(SYNTHETIC_ERRNO(EPERM), | ||
173 | + "Attempted to remove disk file system under \"%s\", and we can't allow that.", | ||
174 | + strna(path)); | ||
175 | + } | ||
176 | + } | ||
177 | + } | ||
178 | |||
179 | - d = fdopendir(fd); | ||
180 | - if (!d) { | ||
181 | - safe_close(fd); | ||
182 | - return -errno; | ||
183 | - } | ||
184 | + FOREACH_DIRENT_ALL(de, d, return -errno) { | ||
185 | + int is_dir; | ||
186 | |||
187 | - if (!(flags & REMOVE_PHYSICAL)) { | ||
188 | - struct statfs sfs; | ||
189 | + if (dot_or_dot_dot(de->d_name)) | ||
190 | + continue; | ||
191 | |||
192 | - if (fstatfs(dirfd(d), &sfs) < 0) | ||
193 | - return -errno; | ||
194 | - } | ||
195 | + is_dir = de->d_type == DT_UNKNOWN ? -1 : de->d_type == DT_DIR; | ||
196 | |||
197 | - if (is_physical_fs(&sfs)) { | ||
198 | - /* We refuse to clean physical file systems with this call, unless explicitly | ||
199 | - * requested. This is extra paranoia just to be sure we never ever remove non-state | ||
200 | - * data. */ | ||
201 | - | ||
202 | - _cleanup_free_ char *path = NULL; | ||
203 | - | ||
204 | - (void) fd_get_path(fd, &path); | ||
205 | - return log_error_errno(SYNTHETIC_ERRNO(EPERM), | ||
206 | - "Attempted to remove disk file system under \"%s\", and we can't allow that.", | ||
207 | - strna(path)); | ||
208 | - } | ||
209 | - } | ||
210 | + r = rm_rf_inner_child(fd, de->d_name, is_dir, flags, root_dev, false); | ||
211 | + if (r == -EISDIR) { | ||
212 | + /* Push the current working state onto the todo list */ | ||
213 | |||
214 | - FOREACH_DIRENT_ALL(de, d, return -errno) { | ||
215 | - int is_dir; | ||
216 | + if (!GREEDY_REALLOC0(todos, allocated, n_todo + 2)) | ||
217 | + return log_oom(); | ||
218 | |||
219 | - if (dot_or_dot_dot(de->d_name)) | ||
220 | - continue; | ||
221 | + _cleanup_free_ char *newdirname = strdup(de->d_name); | ||
222 | + if (!newdirname) | ||
223 | + return log_oom(); | ||
224 | |||
225 | - is_dir = | ||
226 | - de->d_type == DT_UNKNOWN ? -1 : | ||
227 | - de->d_type == DT_DIR; | ||
228 | - | ||
229 | - r = rm_rf_children_inner(dirfd(d), de->d_name, is_dir, flags, root_dev); | ||
230 | - if (r < 0 && r != -ENOENT && ret == 0) | ||
231 | - ret = r; | ||
232 | - } | ||
233 | + int newfd = openat(fd, de->d_name, | ||
234 | + O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME); | ||
235 | + if (newfd >= 0) { | ||
236 | + todos[n_todo++] = (TodoEntry) { TAKE_PTR(d), TAKE_PTR(dirname) }; | ||
237 | + fd = newfd; | ||
238 | + dirname = TAKE_PTR(newdirname); | ||
239 | + | ||
240 | + goto next_fd; | ||
241 | |||
242 | - if (FLAGS_SET(flags, REMOVE_SYNCFS) && syncfs(dirfd(d)) < 0 && ret >= 0) | ||
243 | - ret = -errno; | ||
244 | + } else if (errno != -ENOENT && ret == 0) | ||
245 | + ret = -errno; | ||
246 | + | ||
247 | + } else if (r < 0 && r != -ENOENT && ret == 0) | ||
248 | + ret = r; | ||
249 | + } | ||
250 | + | ||
251 | + if (FLAGS_SET(flags, REMOVE_SYNCFS) && syncfs(fd) < 0 && ret >= 0) | ||
252 | + ret = -errno; | ||
253 | + | ||
254 | + if (n_todo == 0) | ||
255 | + break; | ||
256 | + } | ||
257 | |||
258 | return ret; | ||
259 | } | ||
260 | @@ -250,5 +315,5 @@ | ||
261 | if (FLAGS_SET(flags, REMOVE_ONLY_DIRECTORIES|REMOVE_SUBVOLUME)) | ||
262 | return -EINVAL; | ||
263 | |||
264 | - return rm_rf_children_inner(fd, name, -1, flags, NULL); | ||
265 | + return rm_rf_inner_child(fd, name, -1, flags, NULL, true); | ||
266 | } | ||
diff --git a/meta/recipes-core/systemd/systemd/CVE-2022-3821.patch b/meta/recipes-core/systemd/systemd/CVE-2022-3821.patch new file mode 100644 index 0000000000..f9c6704cfc --- /dev/null +++ b/meta/recipes-core/systemd/systemd/CVE-2022-3821.patch | |||
@@ -0,0 +1,47 @@ | |||
1 | From 9102c625a673a3246d7e73d8737f3494446bad4e Mon Sep 17 00:00:00 2001 | ||
2 | From: Yu Watanabe <watanabe.yu+github@gmail.com> | ||
3 | Date: Thu, 7 Jul 2022 18:27:02 +0900 | ||
4 | Subject: [PATCH] time-util: fix buffer-over-run | ||
5 | |||
6 | Fixes #23928. | ||
7 | |||
8 | CVE: CVE-2022-3821 | ||
9 | Upstream-Status: Backport [https://github.com/systemd/systemd/commit/9102c625a673a3246d7e73d8737f3494446bad4e.patch] | ||
10 | Signed-off-by: Ranjitsinh Rathod <ranjitsinh.rathod@kpit.com> | ||
11 | Comment: Both the hunks refreshed to backport | ||
12 | |||
13 | --- | ||
14 | src/basic/time-util.c | 2 +- | ||
15 | src/test/test-time-util.c | 5 +++++ | ||
16 | 2 files changed, 6 insertions(+), 1 deletion(-) | ||
17 | |||
18 | diff --git a/src/basic/time-util.c b/src/basic/time-util.c | ||
19 | index abbc4ad5cd70..26d59de12348 100644 | ||
20 | --- a/src/basic/time-util.c | ||
21 | +++ b/src/basic/time-util.c | ||
22 | @@ -514,7 +514,7 @@ char *format_timespan(char *buf, size_t | ||
23 | t = b; | ||
24 | } | ||
25 | |||
26 | - n = MIN((size_t) k, l); | ||
27 | + n = MIN((size_t) k, l-1); | ||
28 | |||
29 | l -= n; | ||
30 | p += n; | ||
31 | diff --git a/src/test/test-time-util.c b/src/test/test-time-util.c | ||
32 | index e8e4e2a67bb1..58c5fa9be40c 100644 | ||
33 | --- a/src/test/test-time-util.c | ||
34 | +++ b/src/test/test-time-util.c | ||
35 | @@ -501,6 +501,12 @@ int main(int argc, char *argv[]) { | ||
36 | test_format_timespan(1); | ||
37 | test_format_timespan(USEC_PER_MSEC); | ||
38 | test_format_timespan(USEC_PER_SEC); | ||
39 | + | ||
40 | + /* See issue #23928. */ | ||
41 | + _cleanup_free_ char *buf; | ||
42 | + assert_se(buf = new(char, 5)); | ||
43 | + assert_se(buf == format_timespan(buf, 5, 100005, 1000)); | ||
44 | + | ||
45 | test_timezone_is_valid(); | ||
46 | test_get_timezones(); | ||
47 | test_usec_add(); | ||
diff --git a/meta/recipes-core/systemd/systemd/CVE-2023-26604-1.patch b/meta/recipes-core/systemd/systemd/CVE-2023-26604-1.patch new file mode 100644 index 0000000000..39f9480cf8 --- /dev/null +++ b/meta/recipes-core/systemd/systemd/CVE-2023-26604-1.patch | |||
@@ -0,0 +1,115 @@ | |||
1 | From 612ebf6c913dd0e4197c44909cb3157f5c51a2f0 Mon Sep 17 00:00:00 2001 | ||
2 | From: Lennart Poettering <lennart@poettering.net> | ||
3 | Date: Mon, 31 Aug 2020 19:37:13 +0200 | ||
4 | Subject: [PATCH] pager: set $LESSSECURE whenver we invoke a pager | ||
5 | |||
6 | Some extra safety when invoked via "sudo". With this we address a | ||
7 | genuine design flaw of sudo, and we shouldn't need to deal with this. | ||
8 | But it's still a good idea to disable this surface given how exotic it | ||
9 | is. | ||
10 | |||
11 | Prompted by #5666 | ||
12 | |||
13 | CVE: CVE-2023-26604 | ||
14 | Upstream-Status: Backport [https://github.com/systemd/systemd/pull/17270/commits/612ebf6c913dd0e4197c44909cb3157f5c51a2f0] | ||
15 | Comments: Hunk not refreshed | ||
16 | Signed-off-by: rajmohan r <rajmohan.r@kpit.com> | ||
17 | --- | ||
18 | man/less-variables.xml | 9 +++++++++ | ||
19 | man/systemctl.xml | 1 + | ||
20 | man/systemd.xml | 1 + | ||
21 | src/shared/pager.c | 23 +++++++++++++++++++++-- | ||
22 | 4 files changed, 32 insertions(+), 2 deletions(-) | ||
23 | |||
24 | diff --git a/man/less-variables.xml b/man/less-variables.xml | ||
25 | index 08e513c99f8e..c52511ca8e18 100644 | ||
26 | --- a/man/less-variables.xml | ||
27 | +++ b/man/less-variables.xml | ||
28 | @@ -64,6 +64,15 @@ | ||
29 | the invoking terminal is determined to be UTF-8 compatible).</para></listitem> | ||
30 | </varlistentry> | ||
31 | |||
32 | + <varlistentry id='lesssecure'> | ||
33 | + <term><varname>$SYSTEMD_LESSSECURE</varname></term> | ||
34 | + | ||
35 | + <listitem><para>Takes a boolean argument. Overrides the <varname>$LESSSECURE</varname> environment | ||
36 | + variable when invoking the pager, which controls the "secure" mode of less (which disables commands | ||
37 | + such as <literal>|</literal> which allow to easily shell out to external command lines). By default | ||
38 | + less secure mode is enabled, with this setting it may be disabled.</para></listitem> | ||
39 | + </varlistentry> | ||
40 | + | ||
41 | <varlistentry id='colors'> | ||
42 | <term><varname>$SYSTEMD_COLORS</varname></term> | ||
43 | |||
44 | diff --git a/man/systemctl.xml b/man/systemctl.xml | ||
45 | index 1c5502883700..a3f0c3041a57 100644 | ||
46 | --- a/man/systemctl.xml | ||
47 | +++ b/man/systemctl.xml | ||
48 | @@ -2240,6 +2240,7 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err | ||
49 | <xi:include href="less-variables.xml" xpointer="pager"/> | ||
50 | <xi:include href="less-variables.xml" xpointer="less"/> | ||
51 | <xi:include href="less-variables.xml" xpointer="lesscharset"/> | ||
52 | + <xi:include href="less-variables.xml" xpointer="lesssecure"/> | ||
53 | <xi:include href="less-variables.xml" xpointer="colors"/> | ||
54 | <xi:include href="less-variables.xml" xpointer="urlify"/> | ||
55 | </refsect1> | ||
56 | diff --git a/man/systemd.xml b/man/systemd.xml | ||
57 | index a9040545c2ab..c92cfef77689 100644 | ||
58 | --- a/man/systemd.xml | ||
59 | +++ b/man/systemd.xml | ||
60 | @@ -692,6 +692,7 @@ | ||
61 | <xi:include href="less-variables.xml" xpointer="pager"/> | ||
62 | <xi:include href="less-variables.xml" xpointer="less"/> | ||
63 | <xi:include href="less-variables.xml" xpointer="lesscharset"/> | ||
64 | + <xi:include href="less-variables.xml" xpointer="lesssecure"/> | ||
65 | <xi:include href="less-variables.xml" xpointer="colors"/> | ||
66 | <xi:include href="less-variables.xml" xpointer="urlify"/> | ||
67 | |||
68 | diff --git a/src/shared/pager.c b/src/shared/pager.c | ||
69 | index e03be6d23b2d..9c21881241f5 100644 | ||
70 | --- a/src/shared/pager.c | ||
71 | +++ b/src/shared/pager.c | ||
72 | @@ -9,6 +9,7 @@ | ||
73 | #include <unistd.h> | ||
74 | |||
75 | #include "copy.h" | ||
76 | +#include "env-util.h" | ||
77 | #include "fd-util.h" | ||
78 | #include "fileio.h" | ||
79 | #include "io-util.h" | ||
80 | @@ -152,8 +153,7 @@ int pager_open(PagerFlags flags) { | ||
81 | _exit(EXIT_FAILURE); | ||
82 | } | ||
83 | |||
84 | - /* Initialize a good charset for less. This is | ||
85 | - * particularly important if we output UTF-8 | ||
86 | + /* Initialize a good charset for less. This is particularly important if we output UTF-8 | ||
87 | * characters. */ | ||
88 | less_charset = getenv("SYSTEMD_LESSCHARSET"); | ||
89 | if (!less_charset && is_locale_utf8()) | ||
90 | @@ -164,6 +164,25 @@ int pager_open(PagerFlags flags) { | ||
91 | _exit(EXIT_FAILURE); | ||
92 | } | ||
93 | |||
94 | + /* People might invoke us from sudo, don't needlessly allow less to be a way to shell out | ||
95 | + * privileged stuff. */ | ||
96 | + r = getenv_bool("SYSTEMD_LESSSECURE"); | ||
97 | + if (r == 0) { /* Remove env var if off */ | ||
98 | + if (unsetenv("LESSSECURE") < 0) { | ||
99 | + log_error_errno(errno, "Failed to uset environment variable LESSSECURE: %m"); | ||
100 | + _exit(EXIT_FAILURE); | ||
101 | + } | ||
102 | + } else { | ||
103 | + /* Set env var otherwise */ | ||
104 | + if (r < 0) | ||
105 | + log_warning_errno(r, "Unable to parse $SYSTEMD_LESSSECURE, ignoring: %m"); | ||
106 | + | ||
107 | + if (setenv("LESSSECURE", "1", 1) < 0) { | ||
108 | + log_error_errno(errno, "Failed to set environment variable LESSSECURE: %m"); | ||
109 | + _exit(EXIT_FAILURE); | ||
110 | + } | ||
111 | + } | ||
112 | + | ||
113 | if (pager_args) { | ||
114 | r = loop_write(exe_name_pipe[1], pager_args[0], strlen(pager_args[0]) + 1, false); | ||
115 | if (r < 0) { | ||
diff --git a/meta/recipes-core/systemd/systemd/CVE-2023-26604-2.patch b/meta/recipes-core/systemd/systemd/CVE-2023-26604-2.patch new file mode 100644 index 0000000000..95da7cfad6 --- /dev/null +++ b/meta/recipes-core/systemd/systemd/CVE-2023-26604-2.patch | |||
@@ -0,0 +1,264 @@ | |||
1 | From 1b5b507cd2d1d7a2b053151abb548475ad9c5c3b Mon Sep 17 00:00:00 2001 | ||
2 | From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl> | ||
3 | Date: Mon, 12 Oct 2020 18:57:32 +0200 | ||
4 | Subject: [PATCH] test-login: always test sd_pid_get_owner_uid(), modernize | ||
5 | |||
6 | A long time some function only worked when in a session, and the test | ||
7 | didn't execute them when sd_pid_get_session() failed. Let's always call | ||
8 | them to increase coverage. | ||
9 | |||
10 | While at it, let's test for ==0 not >=0 where we don't expect the function | ||
11 | to return anything except 0 or error. | ||
12 | |||
13 | CVE: CVE-2023-26604 | ||
14 | Upstream-Status: Backport [https://github.com/systemd/systemd/pull/17270/commits/1b5b507cd2d1d7a2b053151abb548475ad9c5c3b.patch] | ||
15 | Comments: Hunk not refreshed | ||
16 | Signed-off-by: rajmohan r <rajmohan.r@kpit.com> | ||
17 | --- | ||
18 | src/libsystemd/sd-login/test-login.c | 131 ++++++++++++++------------- | ||
19 | 1 file changed, 70 insertions(+), 61 deletions(-) | ||
20 | |||
21 | diff --git a/src/libsystemd/sd-login/test-login.c b/src/libsystemd/sd-login/test-login.c | ||
22 | index c0c77e04714b..0494fc77ba18 100644 | ||
23 | --- a/src/libsystemd/sd-login/test-login.c | ||
24 | +++ b/src/libsystemd/sd-login/test-login.c | ||
25 | @@ -5,21 +5,22 @@ | ||
26 | #include "sd-login.h" | ||
27 | |||
28 | #include "alloc-util.h" | ||
29 | +#include "errno-list.h" | ||
30 | #include "fd-util.h" | ||
31 | #include "format-util.h" | ||
32 | #include "log.h" | ||
33 | #include "string-util.h" | ||
34 | #include "strv.h" | ||
35 | #include "time-util.h" | ||
36 | -#include "util.h" | ||
37 | +#include "user-util.h" | ||
38 | |||
39 | static char* format_uids(char **buf, uid_t* uids, int count) { | ||
40 | - int pos = 0, k, inc; | ||
41 | + int pos = 0, inc; | ||
42 | size_t size = (DECIMAL_STR_MAX(uid_t) + 1) * count + 1; | ||
43 | |||
44 | assert_se(*buf = malloc(size)); | ||
45 | |||
46 | - for (k = 0; k < count; k++) { | ||
47 | + for (int k = 0; k < count; k++) { | ||
48 | sprintf(*buf + pos, "%s"UID_FMT"%n", k > 0 ? " " : "", uids[k], &inc); | ||
49 | pos += inc; | ||
50 | } | ||
51 | @@ -30,6 +31,10 @@ static char* format_uids(char **buf, uid_t* uids, int count) { | ||
52 | return *buf; | ||
53 | } | ||
54 | |||
55 | +static const char *e(int r) { | ||
56 | + return r == 0 ? "OK" : errno_to_name(r); | ||
57 | +} | ||
58 | + | ||
59 | static void test_login(void) { | ||
60 | _cleanup_close_pair_ int pair[2] = { -1, -1 }; | ||
61 | _cleanup_free_ char *pp = NULL, *qq = NULL, | ||
62 | @@ -39,65 +44,71 @@ static void test_login(void) { | ||
63 | *seat = NULL, *session = NULL, | ||
64 | *unit = NULL, *user_unit = NULL, *slice = NULL; | ||
65 | int r; | ||
66 | - uid_t u, u2; | ||
67 | - char *t, **seats, **sessions; | ||
68 | + uid_t u, u2 = UID_INVALID; | ||
69 | + char *t, **seats = NULL, **sessions = NULL; | ||
70 | |||
71 | r = sd_pid_get_unit(0, &unit); | ||
72 | - assert_se(r >= 0 || r == -ENODATA); | ||
73 | - log_info("sd_pid_get_unit(0, …) → \"%s\"", strna(unit)); | ||
74 | + log_info("sd_pid_get_unit(0, …) → %s / \"%s\"", e(r), strnull(unit)); | ||
75 | + assert_se(IN_SET(r, 0, -ENODATA)); | ||
76 | |||
77 | r = sd_pid_get_user_unit(0, &user_unit); | ||
78 | - assert_se(r >= 0 || r == -ENODATA); | ||
79 | - log_info("sd_pid_get_user_unit(0, …) → \"%s\"", strna(user_unit)); | ||
80 | + log_info("sd_pid_get_user_unit(0, …) → %s / \"%s\"", e(r), strnull(user_unit)); | ||
81 | + assert_se(IN_SET(r, 0, -ENODATA)); | ||
82 | |||
83 | r = sd_pid_get_slice(0, &slice); | ||
84 | - assert_se(r >= 0 || r == -ENODATA); | ||
85 | - log_info("sd_pid_get_slice(0, …) → \"%s\"", strna(slice)); | ||
86 | + log_info("sd_pid_get_slice(0, …) → %s / \"%s\"", e(r), strnull(slice)); | ||
87 | + assert_se(IN_SET(r, 0, -ENODATA)); | ||
88 | + | ||
89 | + r = sd_pid_get_owner_uid(0, &u2); | ||
90 | + log_info("sd_pid_get_owner_uid(0, …) → %s / "UID_FMT, e(r), u2); | ||
91 | + assert_se(IN_SET(r, 0, -ENODATA)); | ||
92 | |||
93 | r = sd_pid_get_session(0, &session); | ||
94 | - if (r < 0) { | ||
95 | - log_warning_errno(r, "sd_pid_get_session(0, …): %m"); | ||
96 | - if (r == -ENODATA) | ||
97 | - log_info("Seems we are not running in a session, skipping some tests."); | ||
98 | - } else { | ||
99 | - log_info("sd_pid_get_session(0, …) → \"%s\"", session); | ||
100 | - | ||
101 | - assert_se(sd_pid_get_owner_uid(0, &u2) == 0); | ||
102 | - log_info("sd_pid_get_owner_uid(0, …) → "UID_FMT, u2); | ||
103 | - | ||
104 | - assert_se(sd_pid_get_cgroup(0, &cgroup) == 0); | ||
105 | - log_info("sd_pid_get_cgroup(0, …) → \"%s\"", cgroup); | ||
106 | - | ||
107 | - r = sd_uid_get_display(u2, &display_session); | ||
108 | - assert_se(r >= 0 || r == -ENODATA); | ||
109 | - log_info("sd_uid_get_display("UID_FMT", …) → \"%s\"", | ||
110 | - u2, strnull(display_session)); | ||
111 | - | ||
112 | - assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == 0); | ||
113 | - sd_peer_get_session(pair[0], &pp); | ||
114 | - sd_peer_get_session(pair[1], &qq); | ||
115 | - assert_se(streq_ptr(pp, qq)); | ||
116 | - | ||
117 | - r = sd_uid_get_sessions(u2, false, &sessions); | ||
118 | + log_info("sd_pid_get_session(0, …) → %s / \"%s\"", e(r), strnull(session)); | ||
119 | + | ||
120 | + r = sd_pid_get_cgroup(0, &cgroup); | ||
121 | + log_info("sd_pid_get_cgroup(0, …) → %s / \"%s\"", e(r), strnull(cgroup)); | ||
122 | + assert_se(r == 0); | ||
123 | + | ||
124 | + r = sd_uid_get_display(u2, &display_session); | ||
125 | + log_info("sd_uid_get_display("UID_FMT", …) → %s / \"%s\"", u2, e(r), strnull(display_session)); | ||
126 | + if (u2 == UID_INVALID) | ||
127 | + assert_se(r == -EINVAL); | ||
128 | + else | ||
129 | + assert_se(IN_SET(r, 0, -ENODATA)); | ||
130 | + | ||
131 | + assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == 0); | ||
132 | + sd_peer_get_session(pair[0], &pp); | ||
133 | + sd_peer_get_session(pair[1], &qq); | ||
134 | + assert_se(streq_ptr(pp, qq)); | ||
135 | + | ||
136 | + r = sd_uid_get_sessions(u2, false, &sessions); | ||
137 | + assert_se(t = strv_join(sessions, " ")); | ||
138 | + log_info("sd_uid_get_sessions("UID_FMT", …) → %s \"%s\"", u2, e(r), t); | ||
139 | + if (u2 == UID_INVALID) | ||
140 | + assert_se(r == -EINVAL); | ||
141 | + else { | ||
142 | assert_se(r >= 0); | ||
143 | assert_se(r == (int) strv_length(sessions)); | ||
144 | - assert_se(t = strv_join(sessions, " ")); | ||
145 | - strv_free(sessions); | ||
146 | - log_info("sd_uid_get_sessions("UID_FMT", …) → [%i] \"%s\"", u2, r, t); | ||
147 | - free(t); | ||
148 | + } | ||
149 | + sessions = strv_free(sessions); | ||
150 | + free(t); | ||
151 | |||
152 | - assert_se(r == sd_uid_get_sessions(u2, false, NULL)); | ||
153 | + assert_se(r == sd_uid_get_sessions(u2, false, NULL)); | ||
154 | |||
155 | - r = sd_uid_get_seats(u2, false, &seats); | ||
156 | + r = sd_uid_get_seats(u2, false, &seats); | ||
157 | + assert_se(t = strv_join(seats, " ")); | ||
158 | + log_info("sd_uid_get_seats("UID_FMT", …) → %s \"%s\"", u2, e(r), t); | ||
159 | + if (u2 == UID_INVALID) | ||
160 | + assert_se(r == -EINVAL); | ||
161 | + else { | ||
162 | assert_se(r >= 0); | ||
163 | assert_se(r == (int) strv_length(seats)); | ||
164 | - assert_se(t = strv_join(seats, " ")); | ||
165 | - strv_free(seats); | ||
166 | - log_info("sd_uid_get_seats("UID_FMT", …) → [%i] \"%s\"", u2, r, t); | ||
167 | - free(t); | ||
168 | - | ||
169 | - assert_se(r == sd_uid_get_seats(u2, false, NULL)); | ||
170 | } | ||
171 | + seats = strv_free(seats); | ||
172 | + free(t); | ||
173 | + | ||
174 | + assert_se(r == sd_uid_get_seats(u2, false, NULL)); | ||
175 | |||
176 | if (session) { | ||
177 | r = sd_session_is_active(session); | ||
178 | @@ -109,7 +120,7 @@ static void test_login(void) { | ||
179 | log_info("sd_session_is_remote(\"%s\") → %s", session, yes_no(r)); | ||
180 | |||
181 | r = sd_session_get_state(session, &state); | ||
182 | - assert_se(r >= 0); | ||
183 | + assert_se(r == 0); | ||
184 | log_info("sd_session_get_state(\"%s\") → \"%s\"", session, state); | ||
185 | |||
186 | assert_se(sd_session_get_uid(session, &u) >= 0); | ||
187 | @@ -123,16 +134,16 @@ static void test_login(void) { | ||
188 | log_info("sd_session_get_class(\"%s\") → \"%s\"", session, class); | ||
189 | |||
190 | r = sd_session_get_display(session, &display); | ||
191 | - assert_se(r >= 0 || r == -ENODATA); | ||
192 | + assert_se(IN_SET(r, 0, -ENODATA)); | ||
193 | log_info("sd_session_get_display(\"%s\") → \"%s\"", session, strna(display)); | ||
194 | |||
195 | r = sd_session_get_remote_user(session, &remote_user); | ||
196 | - assert_se(r >= 0 || r == -ENODATA); | ||
197 | + assert_se(IN_SET(r, 0, -ENODATA)); | ||
198 | log_info("sd_session_get_remote_user(\"%s\") → \"%s\"", | ||
199 | session, strna(remote_user)); | ||
200 | |||
201 | r = sd_session_get_remote_host(session, &remote_host); | ||
202 | - assert_se(r >= 0 || r == -ENODATA); | ||
203 | + assert_se(IN_SET(r, 0, -ENODATA)); | ||
204 | log_info("sd_session_get_remote_host(\"%s\") → \"%s\"", | ||
205 | session, strna(remote_host)); | ||
206 | |||
207 | @@ -161,7 +172,7 @@ static void test_login(void) { | ||
208 | assert_se(r == -ENODATA); | ||
209 | } | ||
210 | |||
211 | - assert_se(sd_uid_get_state(u, &state2) >= 0); | ||
212 | + assert_se(sd_uid_get_state(u, &state2) == 0); | ||
213 | log_info("sd_uid_get_state("UID_FMT", …) → %s", u, state2); | ||
214 | } | ||
215 | |||
216 | @@ -173,11 +184,11 @@ static void test_login(void) { | ||
217 | assert_se(sd_uid_is_on_seat(u, 0, seat) > 0); | ||
218 | |||
219 | r = sd_seat_get_active(seat, &session2, &u2); | ||
220 | - assert_se(r >= 0); | ||
221 | + assert_se(r == 0); | ||
222 | log_info("sd_seat_get_active(\"%s\", …) → \"%s\", "UID_FMT, seat, session2, u2); | ||
223 | |||
224 | r = sd_uid_is_on_seat(u, 1, seat); | ||
225 | - assert_se(r >= 0); | ||
226 | + assert_se(IN_SET(r, 0, 1)); | ||
227 | assert_se(!!r == streq(session, session2)); | ||
228 | |||
229 | r = sd_seat_get_sessions(seat, &sessions, &uids, &n); | ||
230 | @@ -185,8 +196,8 @@ static void test_login(void) { | ||
231 | assert_se(r == (int) strv_length(sessions)); | ||
232 | assert_se(t = strv_join(sessions, " ")); | ||
233 | strv_free(sessions); | ||
234 | - log_info("sd_seat_get_sessions(\"%s\", …) → %i, \"%s\", [%i] {%s}", | ||
235 | - seat, r, t, n, format_uids(&buf, uids, n)); | ||
236 | + log_info("sd_seat_get_sessions(\"%s\", …) → %s, \"%s\", [%u] {%s}", | ||
237 | + seat, e(r), t, n, format_uids(&buf, uids, n)); | ||
238 | free(t); | ||
239 | |||
240 | assert_se(sd_seat_get_sessions(seat, NULL, NULL, NULL) == r); | ||
241 | @@ -204,7 +215,7 @@ static void test_login(void) { | ||
242 | |||
243 | r = sd_seat_get_active(NULL, &t, NULL); | ||
244 | assert_se(IN_SET(r, 0, -ENODATA)); | ||
245 | - log_info("sd_seat_get_active(NULL, …) (active session on current seat) → %s", strnull(t)); | ||
246 | + log_info("sd_seat_get_active(NULL, …) (active session on current seat) → %s / \"%s\"", e(r), strnull(t)); | ||
247 | free(t); | ||
248 | |||
249 | r = sd_get_sessions(&sessions); | ||
250 | @@ -244,13 +255,11 @@ static void test_login(void) { | ||
251 | |||
252 | static void test_monitor(void) { | ||
253 | sd_login_monitor *m = NULL; | ||
254 | - unsigned n; | ||
255 | int r; | ||
256 | |||
257 | - r = sd_login_monitor_new("session", &m); | ||
258 | - assert_se(r >= 0); | ||
259 | + assert_se(sd_login_monitor_new("session", &m) == 0); | ||
260 | |||
261 | - for (n = 0; n < 5; n++) { | ||
262 | + for (unsigned n = 0; n < 5; n++) { | ||
263 | struct pollfd pollfd = {}; | ||
264 | usec_t timeout, nw; | ||
diff --git a/meta/recipes-core/systemd/systemd/CVE-2023-26604-3.patch b/meta/recipes-core/systemd/systemd/CVE-2023-26604-3.patch new file mode 100644 index 0000000000..f02f62b772 --- /dev/null +++ b/meta/recipes-core/systemd/systemd/CVE-2023-26604-3.patch | |||
@@ -0,0 +1,182 @@ | |||
1 | From 0a42426d797406b4b01a0d9c13bb759c2629d108 Mon Sep 17 00:00:00 2001 | ||
2 | From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl> | ||
3 | Date: Wed, 7 Oct 2020 11:15:05 +0200 | ||
4 | Subject: [PATCH] pager: make pager secure when under euid is changed or | ||
5 | explicitly requested | ||
6 | |||
7 | The variable is renamed to SYSTEMD_PAGERSECURE (because it's not just about | ||
8 | less now), and we automatically enable secure mode in certain cases, but not | ||
9 | otherwise. | ||
10 | |||
11 | This approach is more nuanced, but should provide a better experience for | ||
12 | users: | ||
13 | |||
14 | - Previusly we would set LESSSECURE=1 and trust the pager to make use of | ||
15 | it. But this has an effect only on less. We need to not start pagers which | ||
16 | are insecure when in secure mode. In particular more is like that and is a | ||
17 | very popular pager. | ||
18 | |||
19 | - We don't enable secure mode always, which means that those other pagers can | ||
20 | reasonably used. | ||
21 | |||
22 | - We do the right thing by default, but the user has ultimate control by | ||
23 | setting SYSTEMD_PAGERSECURE. | ||
24 | |||
25 | Fixes #5666. | ||
26 | |||
27 | v2: | ||
28 | - also check $PKEXEC_UID | ||
29 | |||
30 | v3: | ||
31 | - use 'sd_pid_get_owner_uid() != geteuid()' as the condition | ||
32 | |||
33 | CVE: CVE-2023-26604 | ||
34 | Upstream-Status: Backport [https://github.com/systemd/systemd/pull/17270/commits/0a42426d797406b4b01a0d9c13bb759c2629d108] | ||
35 | Comments: Hunk refreshed | ||
36 | Signed-off-by: rajmohan r <rajmohan.r@kpit.com> | ||
37 | --- | ||
38 | man/less-variables.xml | 30 +++++++++++++++---- | ||
39 | src/shared/pager.c | 63 ++++++++++++++++++++++++++------------- | ||
40 | 2 files changed, 66 insertions(+), 27 deletions(-) | ||
41 | |||
42 | diff --git a/man/less-variables.xml b/man/less-variables.xml | ||
43 | index c52511c..049e9f7 100644 | ||
44 | --- a/man/less-variables.xml | ||
45 | +++ b/man/less-variables.xml | ||
46 | @@ -65,12 +65,30 @@ | ||
47 | </varlistentry> | ||
48 | |||
49 | <varlistentry id='lesssecure'> | ||
50 | - <term><varname>$SYSTEMD_LESSSECURE</varname></term> | ||
51 | - | ||
52 | - <listitem><para>Takes a boolean argument. Overrides the <varname>$LESSSECURE</varname> environment | ||
53 | - variable when invoking the pager, which controls the "secure" mode of less (which disables commands | ||
54 | - such as <literal>|</literal> which allow to easily shell out to external command lines). By default | ||
55 | - less secure mode is enabled, with this setting it may be disabled.</para></listitem> | ||
56 | + <term><varname>$SYSTEMD_PAGERSECURE</varname></term> | ||
57 | + | ||
58 | + <listitem><para>Takes a boolean argument. When true, the "secure" mode of the pager is enabled; if | ||
59 | + false, disabled. If <varname>$SYSTEMD_PAGERSECURE</varname> is not set at all, secure mode is enabled | ||
60 | + if the effective UID is not the same as the owner of the login session, see <citerefentry | ||
61 | + project='man-pages'><refentrytitle>geteuid</refentrytitle><manvolnum>2</manvolnum></citerefentry> and | ||
62 | + <citerefentry><refentrytitle>sd_pid_get_owner_uid</refentrytitle><manvolnum>3</manvolnum></citerefentry>. | ||
63 | + In secure mode, <option>LESSSECURE=1</option> will be set when invoking the pager, and the pager shall | ||
64 | + disable commands that open or create new files or start new subprocesses. When | ||
65 | + <varname>$SYSTEMD_PAGERSECURE</varname> is not set at all, pagers which are not known to implement | ||
66 | + secure mode will not be used. (Currently only | ||
67 | + <citerefentry><refentrytitle>less</refentrytitle><manvolnum>1</manvolnum></citerefentry> implements | ||
68 | + secure mode.)</para> | ||
69 | + | ||
70 | + <para>Note: when commands are invoked with elevated privileges, for example under <citerefentry | ||
71 | + project='man-pages'><refentrytitle>sudo</refentrytitle><manvolnum>8</manvolnum></citerefentry> or | ||
72 | + <citerefentry | ||
73 | + project='die-net'><refentrytitle>pkexec</refentrytitle><manvolnum>1</manvolnum></citerefentry>, care | ||
74 | + must be taken to ensure that unintended interactive features are not enabled. "Secure" mode for the | ||
75 | + pager may be enabled automatically as describe above. Setting <varname>SYSTEMD_PAGERSECURE=0</varname> | ||
76 | + or not removing it from the inherited environment allows the user to invoke arbitrary commands. Note | ||
77 | + that if the <varname>$SYSTEMD_PAGER</varname> or <varname>$PAGER</varname> variables are to be | ||
78 | + honoured, <varname>$SYSTEMD_PAGERSECURE</varname> must be set too. It might be reasonable to completly | ||
79 | + disable the pager using <option>--no-pager</option> instead.</para></listitem> | ||
80 | </varlistentry> | ||
81 | |||
82 | <varlistentry id='colors'> | ||
83 | diff --git a/src/shared/pager.c b/src/shared/pager.c | ||
84 | index a3b6576..a72d9ea 100644 | ||
85 | --- a/src/shared/pager.c | ||
86 | +++ b/src/shared/pager.c | ||
87 | @@ -8,6 +8,8 @@ | ||
88 | #include <sys/prctl.h> | ||
89 | #include <unistd.h> | ||
90 | |||
91 | +#include "sd-login.h" | ||
92 | + | ||
93 | #include "copy.h" | ||
94 | #include "env-util.h" | ||
95 | #include "fd-util.h" | ||
96 | @@ -164,25 +166,42 @@ int pager_open(PagerFlags flags) { | ||
97 | } | ||
98 | |||
99 | /* People might invoke us from sudo, don't needlessly allow less to be a way to shell out | ||
100 | - * privileged stuff. */ | ||
101 | - r = getenv_bool("SYSTEMD_LESSSECURE"); | ||
102 | - if (r == 0) { /* Remove env var if off */ | ||
103 | - if (unsetenv("LESSSECURE") < 0) { | ||
104 | - log_error_errno(errno, "Failed to uset environment variable LESSSECURE: %m"); | ||
105 | - _exit(EXIT_FAILURE); | ||
106 | - } | ||
107 | - } else { | ||
108 | - /* Set env var otherwise */ | ||
109 | + * privileged stuff. If the user set $SYSTEMD_PAGERSECURE, trust their configuration of the | ||
110 | + * pager. If they didn't, use secure mode when under euid is changed. If $SYSTEMD_PAGERSECURE | ||
111 | + * wasn't explicitly set, and we autodetect the need for secure mode, only use the pager we | ||
112 | + * know to be good. */ | ||
113 | + int use_secure_mode = getenv_bool("SYSTEMD_PAGERSECURE"); | ||
114 | + bool trust_pager = use_secure_mode >= 0; | ||
115 | + if (use_secure_mode == -ENXIO) { | ||
116 | + uid_t uid; | ||
117 | + | ||
118 | + r = sd_pid_get_owner_uid(0, &uid); | ||
119 | if (r < 0) | ||
120 | - log_warning_errno(r, "Unable to parse $SYSTEMD_LESSSECURE, ignoring: %m"); | ||
121 | + log_debug_errno(r, "sd_pid_get_owner_uid() failed, enabling pager secure mode: %m"); | ||
122 | |||
123 | - if (setenv("LESSSECURE", "1", 1) < 0) { | ||
124 | - log_error_errno(errno, "Failed to set environment variable LESSSECURE: %m"); | ||
125 | - _exit(EXIT_FAILURE); | ||
126 | - } | ||
127 | + use_secure_mode = r < 0 || uid != geteuid(); | ||
128 | + | ||
129 | + } else if (use_secure_mode < 0) { | ||
130 | + log_warning_errno(use_secure_mode, "Unable to parse $SYSTEMD_PAGERSECURE, assuming true: %m"); | ||
131 | + use_secure_mode = true; | ||
132 | } | ||
133 | |||
134 | - if (pager_args) { | ||
135 | + /* We generally always set variables used by less, even if we end up using a different pager. | ||
136 | + * They shouldn't hurt in any case, and ideally other pagers would look at them too. */ | ||
137 | + if (use_secure_mode) | ||
138 | + r = setenv("LESSSECURE", "1", 1); | ||
139 | + else | ||
140 | + r = unsetenv("LESSSECURE"); | ||
141 | + if (r < 0) { | ||
142 | + log_error_errno(errno, "Failed to adjust environment variable LESSSECURE: %m"); | ||
143 | + _exit(EXIT_FAILURE); | ||
144 | + } | ||
145 | + | ||
146 | + if (trust_pager && pager_args) { /* The pager config might be set globally, and we cannot | ||
147 | + * know if the user adjusted it to be appropriate for the | ||
148 | + * secure mode. Thus, start the pager specified through | ||
149 | + * envvars only when $SYSTEMD_PAGERSECURE was explicitly set | ||
150 | + * as well. */ | ||
151 | r = loop_write(exe_name_pipe[1], pager_args[0], strlen(pager_args[0]) + 1, false); | ||
152 | if (r < 0) { | ||
153 | log_error_errno(r, "Failed to write pager name to socket: %m"); | ||
154 | @@ -194,13 +213,14 @@ int pager_open(PagerFlags flags) { | ||
155 | "Failed to execute '%s', using fallback pagers: %m", pager_args[0]); | ||
156 | } | ||
157 | |||
158 | - /* Debian's alternatives command for pagers is | ||
159 | - * called 'pager'. Note that we do not call | ||
160 | - * sensible-pagers here, since that is just a | ||
161 | - * shell script that implements a logic that | ||
162 | - * is similar to this one anyway, but is | ||
163 | - * Debian-specific. */ | ||
164 | + /* Debian's alternatives command for pagers is called 'pager'. Note that we do not call | ||
165 | + * sensible-pagers here, since that is just a shell script that implements a logic that is | ||
166 | + * similar to this one anyway, but is Debian-specific. */ | ||
167 | FOREACH_STRING(exe, "pager", "less", "more") { | ||
168 | + /* Only less implements secure mode right now. */ | ||
169 | + if (use_secure_mode && !streq(exe, "less")) | ||
170 | + continue; | ||
171 | + | ||
172 | r = loop_write(exe_name_pipe[1], exe, strlen(exe) + 1, false); | ||
173 | if (r < 0) { | ||
174 | log_error_errno(r, "Failed to write pager name to socket: %m"); | ||
175 | @@ -211,6 +231,7 @@ int pager_open(PagerFlags flags) { | ||
176 | "Failed to execute '%s', using next fallback pager: %m", exe); | ||
177 | } | ||
178 | |||
179 | + /* Our builtin is also very secure. */ | ||
180 | r = loop_write(exe_name_pipe[1], "(built-in)", strlen("(built-in)") + 1, false); | ||
181 | if (r < 0) { | ||
182 | log_error_errno(r, "Failed to write pager name to socket: %m"); | ||
diff --git a/meta/recipes-core/systemd/systemd/CVE-2023-26604-4.patch b/meta/recipes-core/systemd/systemd/CVE-2023-26604-4.patch new file mode 100644 index 0000000000..bc6b0a91c2 --- /dev/null +++ b/meta/recipes-core/systemd/systemd/CVE-2023-26604-4.patch | |||
@@ -0,0 +1,32 @@ | |||
1 | From b8f736b30e20a2b44e7c34bb4e43b0d97ae77e3c Mon Sep 17 00:00:00 2001 | ||
2 | From: Lennart Poettering <lennart@poettering.net> | ||
3 | Date: Thu, 15 Oct 2020 10:54:48 +0200 | ||
4 | Subject: [PATCH] pager: lets check SYSTEMD_PAGERSECURE with secure_getenv() | ||
5 | |||
6 | I can't think of any real vulnerability about this, but it still feels | ||
7 | better to check a variable with "secure" in its name with | ||
8 | secure_getenv() rather than plain getenv(). | ||
9 | |||
10 | Paranoia FTW! | ||
11 | |||
12 | CVE: CVE-2023-26604 | ||
13 | Upstream-Status: Backport [https://github.com/systemd/systemd/pull/17359/commits/b8f736b30e20a2b44e7c34bb4e43b0d97ae77e3c] | ||
14 | Comments: Hunk refreshed | ||
15 | Signed-off-by: rajmohan r <rajmohan.r@kpit.com> | ||
16 | --- | ||
17 | src/shared/pager.c | 2 +- | ||
18 | 1 file changed, 1 insertion(+), 1 deletion(-) | ||
19 | |||
20 | diff --git a/src/shared/pager.c b/src/shared/pager.c | ||
21 | index a72d9ea..250519c 100644 | ||
22 | --- a/src/shared/pager.c | ||
23 | +++ b/src/shared/pager.c | ||
24 | @@ -170,7 +170,7 @@ int pager_open(PagerFlags flags) { | ||
25 | * pager. If they didn't, use secure mode when under euid is changed. If $SYSTEMD_PAGERSECURE | ||
26 | * wasn't explicitly set, and we autodetect the need for secure mode, only use the pager we | ||
27 | * know to be good. */ | ||
28 | - int use_secure_mode = getenv_bool("SYSTEMD_PAGERSECURE"); | ||
29 | + int use_secure_mode = getenv_bool_secure("SYSTEMD_PAGERSECURE"); | ||
30 | bool trust_pager = use_secure_mode >= 0; | ||
31 | if (use_secure_mode == -ENXIO) { | ||
32 | uid_t uid; | ||
diff --git a/meta/recipes-core/systemd/systemd/basic-pass-allocation-info-for-ordered-set-new-and-introd.patch b/meta/recipes-core/systemd/systemd/basic-pass-allocation-info-for-ordered-set-new-and-introd.patch new file mode 100644 index 0000000000..86d9b0499a --- /dev/null +++ b/meta/recipes-core/systemd/systemd/basic-pass-allocation-info-for-ordered-set-new-and-introd.patch | |||
@@ -0,0 +1,78 @@ | |||
1 | From 1f25c71d9d0b5fe6cf383c347dcebc2443a99fe1 Mon Sep 17 00:00:00 2001 | ||
2 | From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl> | ||
3 | Date: Tue, 1 Sep 2020 12:42:35 +0200 | ||
4 | Subject: [PATCH] basic: pass allocation info for ordered_set_new() and | ||
5 | introduce ordered_set_ensure_put() | ||
6 | |||
7 | Upstream-Status: Backport [https://github.com/systemd/systemd-stable/commit/1f25c71d9d0b5fe6cf383c347dcebc2443a99fe1] | ||
8 | Signed-off-by: Ranjitsinh Rathod <ranjitsinh.rathod@kpit.com> | ||
9 | |||
10 | --- | ||
11 | src/basic/ordered-set.c | 21 +++++++++++++++++++++ | ||
12 | src/basic/ordered-set.h | 18 +++++++----------- | ||
13 | 2 files changed, 28 insertions(+), 11 deletions(-) | ||
14 | |||
15 | diff --git a/src/basic/ordered-set.c b/src/basic/ordered-set.c | ||
16 | index 7fdb47e064..fb82c17b5a 100644 | ||
17 | --- a/src/basic/ordered-set.c | ||
18 | +++ b/src/basic/ordered-set.c | ||
19 | @@ -4,6 +4,27 @@ | ||
20 | #include "ordered-set.h" | ||
21 | #include "strv.h" | ||
22 | |||
23 | +int _ordered_set_ensure_allocated(OrderedSet **s, const struct hash_ops *ops HASHMAP_DEBUG_PARAMS) { | ||
24 | + if (*s) | ||
25 | + return 0; | ||
26 | + | ||
27 | + *s = _ordered_set_new(ops HASHMAP_DEBUG_PASS_ARGS); | ||
28 | + if (!*s) | ||
29 | + return -ENOMEM; | ||
30 | + | ||
31 | + return 0; | ||
32 | +} | ||
33 | + | ||
34 | +int _ordered_set_ensure_put(OrderedSet **s, const struct hash_ops *ops, void *p HASHMAP_DEBUG_PARAMS) { | ||
35 | + int r; | ||
36 | + | ||
37 | + r = _ordered_set_ensure_allocated(s, ops HASHMAP_DEBUG_PASS_ARGS); | ||
38 | + if (r < 0) | ||
39 | + return r; | ||
40 | + | ||
41 | + return ordered_set_put(*s, p); | ||
42 | +} | ||
43 | + | ||
44 | int ordered_set_consume(OrderedSet *s, void *p) { | ||
45 | int r; | ||
46 | |||
47 | diff --git a/src/basic/ordered-set.h b/src/basic/ordered-set.h | ||
48 | index a42a57eb49..2c241a808b 100644 | ||
49 | --- a/src/basic/ordered-set.h | ||
50 | +++ b/src/basic/ordered-set.h | ||
51 | @@ -7,20 +7,16 @@ | ||
52 | |||
53 | typedef struct OrderedSet OrderedSet; | ||
54 | |||
55 | -static inline OrderedSet* ordered_set_new(const struct hash_ops *ops) { | ||
56 | - return (OrderedSet*) ordered_hashmap_new(ops); | ||
57 | +static inline OrderedSet* _ordered_set_new(const struct hash_ops *ops HASHMAP_DEBUG_PARAMS) { | ||
58 | + return (OrderedSet*) internal_ordered_hashmap_new(ops HASHMAP_DEBUG_PASS_ARGS); | ||
59 | } | ||
60 | +#define ordered_set_new(ops) _ordered_set_new(ops HASHMAP_DEBUG_SRC_ARGS) | ||
61 | |||
62 | -static inline int ordered_set_ensure_allocated(OrderedSet **s, const struct hash_ops *ops) { | ||
63 | - if (*s) | ||
64 | - return 0; | ||
65 | +int _ordered_set_ensure_allocated(OrderedSet **s, const struct hash_ops *ops HASHMAP_DEBUG_PARAMS); | ||
66 | +#define ordered_set_ensure_allocated(s, ops) _ordered_set_ensure_allocated(s, ops HASHMAP_DEBUG_SRC_ARGS) | ||
67 | |||
68 | - *s = ordered_set_new(ops); | ||
69 | - if (!*s) | ||
70 | - return -ENOMEM; | ||
71 | - | ||
72 | - return 0; | ||
73 | -} | ||
74 | +int _ordered_set_ensure_put(OrderedSet **s, const struct hash_ops *ops, void *p HASHMAP_DEBUG_PARAMS); | ||
75 | +#define ordered_set_ensure_put(s, hash_ops, key) _ordered_set_ensure_put(s, hash_ops, key HASHMAP_DEBUG_SRC_ARGS) | ||
76 | |||
77 | static inline OrderedSet* ordered_set_free(OrderedSet *s) { | ||
78 | return (OrderedSet*) ordered_hashmap_free((OrderedHashmap*) s); | ||
diff --git a/meta/recipes-core/systemd/systemd/introduce-ordered_set_clear-free-with-destructor.patch b/meta/recipes-core/systemd/systemd/introduce-ordered_set_clear-free-with-destructor.patch new file mode 100644 index 0000000000..42b6e05b55 --- /dev/null +++ b/meta/recipes-core/systemd/systemd/introduce-ordered_set_clear-free-with-destructor.patch | |||
@@ -0,0 +1,35 @@ | |||
1 | From d38a6476aad3f2cc80a2a4bc11f3898cc06a70f5 Mon Sep 17 00:00:00 2001 | ||
2 | From: Yu Watanabe <watanabe.yu+github@gmail.com> | ||
3 | Date: Mon, 26 Apr 2021 23:52:40 +0900 | ||
4 | Subject: [PATCH] ordered-set: introduce | ||
5 | ordered_set_clear/free_with_destructor() | ||
6 | |||
7 | Upstream-Status: Backport [https://github.com/systemd/systemd-stable/commit/d38a6476aad3f2cc80a2a4bc11f3898cc06a70f5] | ||
8 | Signed-off-by: Ranjitsinh Rathod <ranjitsinh.rathod@kpit.com> | ||
9 | |||
10 | --- | ||
11 | src/basic/ordered-set.h | 11 +++++++++++ | ||
12 | 1 file changed, 11 insertions(+) | ||
13 | |||
14 | diff --git a/src/basic/ordered-set.h b/src/basic/ordered-set.h | ||
15 | index a377f20b1f..64df41766f 100644 | ||
16 | --- a/src/basic/ordered-set.h | ||
17 | +++ b/src/basic/ordered-set.h | ||
18 | @@ -63,6 +63,17 @@ void ordered_set_print(FILE *f, const char *field, OrderedSet *s); | ||
19 | #define ORDERED_SET_FOREACH(e, s, i) \ | ||
20 | for ((i) = ITERATOR_FIRST; ordered_set_iterate((s), &(i), (void**)&(e)); ) | ||
21 | |||
22 | +#define ordered_set_clear_with_destructor(s, f) \ | ||
23 | + ({ \ | ||
24 | + OrderedSet *_s = (s); \ | ||
25 | + void *_item; \ | ||
26 | + while ((_item = ordered_set_steal_first(_s))) \ | ||
27 | + f(_item); \ | ||
28 | + _s; \ | ||
29 | + }) | ||
30 | +#define ordered_set_free_with_destructor(s, f) \ | ||
31 | + ordered_set_free(ordered_set_clear_with_destructor(s, f)) | ||
32 | + | ||
33 | DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedSet*, ordered_set_free); | ||
34 | DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedSet*, ordered_set_free_free); | ||
35 | |||
diff --git a/meta/recipes-core/systemd/systemd/network-add-skeleton-of-request-queue.patch b/meta/recipes-core/systemd/systemd/network-add-skeleton-of-request-queue.patch new file mode 100644 index 0000000000..06c523834d --- /dev/null +++ b/meta/recipes-core/systemd/systemd/network-add-skeleton-of-request-queue.patch | |||
@@ -0,0 +1,285 @@ | |||
1 | From 19d9a5adf0c1a6b5a243eea0390f6f6526d569de Mon Sep 17 00:00:00 2001 | ||
2 | From: Yu Watanabe <watanabe.yu+github@gmail.com> | ||
3 | Date: Fri, 7 May 2021 15:39:16 +0900 | ||
4 | Subject: [PATCH] network: add skeleton of request queue | ||
5 | |||
6 | This will be used in later commits. | ||
7 | |||
8 | Upstream-Status: Backport [https://github.com/systemd/systemd-stable/commit/19d9a5adf0c1a6b5a243eea0390f6f6526d569de] | ||
9 | Signed-off-by: Ranjitsinh Rathod <ranjitsinh.rathod@kpit.com> | ||
10 | |||
11 | --- | ||
12 | src/network/meson.build | 2 + | ||
13 | src/network/networkd-link.c | 20 +++++- | ||
14 | src/network/networkd-manager.c | 7 ++ | ||
15 | src/network/networkd-manager.h | 2 + | ||
16 | src/network/networkd-queue.c | 121 +++++++++++++++++++++++++++++++++ | ||
17 | src/network/networkd-queue.h | 42 ++++++++++++ | ||
18 | 6 files changed, 192 insertions(+), 2 deletions(-) | ||
19 | create mode 100644 src/network/networkd-queue.c | ||
20 | create mode 100644 src/network/networkd-queue.h | ||
21 | |||
22 | diff --git a/src/network/meson.build b/src/network/meson.build | ||
23 | index 4fca3106dc..a8b9232e64 100644 | ||
24 | --- a/src/network/meson.build | ||
25 | +++ b/src/network/meson.build | ||
26 | @@ -105,6 +105,8 @@ sources = files(''' | ||
27 | networkd-network.h | ||
28 | networkd-nexthop.c | ||
29 | networkd-nexthop.h | ||
30 | + networkd-queue.c | ||
31 | + networkd-queue.h | ||
32 | networkd-route.c | ||
33 | networkd-route.h | ||
34 | networkd-routing-policy-rule.c | ||
35 | diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c | ||
36 | index 34359b2541..2f33305a27 100644 | ||
37 | --- a/src/network/networkd-link.c | ||
38 | +++ b/src/network/networkd-link.c | ||
39 | @@ -30,6 +30,7 @@ | ||
40 | #include "networkd-manager.h" | ||
41 | #include "networkd-ndisc.h" | ||
42 | #include "networkd-neighbor.h" | ||
43 | +#include "networkd-queue.h" | ||
44 | #include "networkd-radv.h" | ||
45 | #include "networkd-routing-policy-rule.h" | ||
46 | #include "networkd-wifi.h" | ||
47 | |||
48 | @@ -2232,6 +2244,8 @@ static int link_reconfigure_internal(Link *link, sd_netlink_message *m, bool for | ||
49 | if (r < 0) | ||
50 | return r; | ||
51 | |||
52 | + link_drop_requests(link); | ||
53 | + | ||
54 | r = link_drop_config(link); | ||
55 | if (r < 0) | ||
56 | return r; | ||
57 | @@ -2664,6 +2678,8 @@ static int link_carrier_lost(Link *link) { | ||
58 | return r; | ||
59 | } | ||
60 | |||
61 | + link_drop_requests(link); | ||
62 | + | ||
63 | r = link_drop_config(link); | ||
64 | if (r < 0) | ||
65 | return r; | ||
66 | diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c | ||
67 | index 562ce5ca54..fd576169a9 100644 | ||
68 | --- a/src/network/networkd-manager.c | ||
69 | +++ b/src/network/networkd-manager.c | ||
70 | @@ -34,6 +34,7 @@ | ||
71 | #include "networkd-manager-bus.h" | ||
72 | #include "networkd-manager.h" | ||
73 | #include "networkd-network-bus.h" | ||
74 | +#include "networkd-queue.h" | ||
75 | #include "networkd-speed-meter.h" | ||
76 | #include "ordered-set.h" | ||
77 | #include "path-util.h" | ||
78 | @@ -406,6 +407,10 @@ int manager_new(Manager **ret) { | ||
79 | if (r < 0) | ||
80 | return r; | ||
81 | |||
82 | + r = sd_event_add_post(m->event, NULL, manager_process_requests, m); | ||
83 | + if (r < 0) | ||
84 | + return r; | ||
85 | + | ||
86 | r = manager_connect_rtnl(m); | ||
87 | if (r < 0) | ||
88 | return r; | ||
89 | @@ -446,6 +451,8 @@ Manager* manager_free(Manager *m) { | ||
90 | |||
91 | free(m->state_file); | ||
92 | |||
93 | + m->request_queue = ordered_set_free_with_destructor(m->request_queue, request_free); | ||
94 | + | ||
95 | while ((a = hashmap_first_key(m->dhcp6_prefixes))) | ||
96 | (void) dhcp6_prefix_remove(m, a); | ||
97 | m->dhcp6_prefixes = hashmap_free(m->dhcp6_prefixes); | ||
98 | diff --git a/src/network/networkd-manager.h b/src/network/networkd-manager.h | ||
99 | index 301b97c1a1..26e8802871 100644 | ||
100 | --- a/src/network/networkd-manager.h | ||
101 | +++ b/src/network/networkd-manager.h | ||
102 | @@ -91,6 +91,8 @@ struct Manager { | ||
103 | usec_t speed_meter_usec_old; | ||
104 | |||
105 | bool dhcp4_prefix_root_cannot_set_table; | ||
106 | + | ||
107 | + OrderedSet *request_queue; | ||
108 | }; | ||
109 | |||
110 | int manager_new(Manager **ret); | ||
111 | diff --git a/src/network/networkd-queue.c b/src/network/networkd-queue.c | ||
112 | new file mode 100644 | ||
113 | index 0000000000..24bb2c845d | ||
114 | --- /dev/null | ||
115 | +++ b/src/network/networkd-queue.c | ||
116 | @@ -0,0 +1,121 @@ | ||
117 | +/* SPDX-License-Identifier: LGPL-2.1-or-later */ | ||
118 | + | ||
119 | +#include "networkd-address.h" | ||
120 | +#include "networkd-manager.h" | ||
121 | +#include "networkd-neighbor.h" | ||
122 | +#include "networkd-nexthop.h" | ||
123 | +#include "networkd-route.h" | ||
124 | +#include "networkd-routing-policy-rule.h" | ||
125 | +#include "networkd-queue.h" | ||
126 | + | ||
127 | +static void request_free_object(RequestType type, void *object) { | ||
128 | + switch(type) { | ||
129 | + default: | ||
130 | + assert_not_reached("invalid request type."); | ||
131 | + } | ||
132 | +} | ||
133 | + | ||
134 | +Request *request_free(Request *req) { | ||
135 | + if (!req) | ||
136 | + return NULL; | ||
137 | + | ||
138 | + if (req->on_free) | ||
139 | + req->on_free(req); | ||
140 | + if (req->consume_object) | ||
141 | + request_free_object(req->type, req->object); | ||
142 | + if (req->link && req->link->manager) | ||
143 | + ordered_set_remove(req->link->manager->request_queue, req); | ||
144 | + link_unref(req->link); | ||
145 | + | ||
146 | + return mfree(req); | ||
147 | +} | ||
148 | + | ||
149 | +DEFINE_TRIVIAL_CLEANUP_FUNC(Request*, request_free); | ||
150 | + | ||
151 | +void request_drop(Request *req) { | ||
152 | + if (req->message_counter) | ||
153 | + (*req->message_counter)--; | ||
154 | + | ||
155 | + request_free(req); | ||
156 | +} | ||
157 | + | ||
158 | +int link_queue_request( | ||
159 | + Link *link, | ||
160 | + RequestType type, | ||
161 | + void *object, | ||
162 | + bool consume_object, | ||
163 | + unsigned *message_counter, | ||
164 | + link_netlink_message_handler_t netlink_handler, | ||
165 | + Request **ret) { | ||
166 | + | ||
167 | + _cleanup_(request_freep) Request *req = NULL; | ||
168 | + int r; | ||
169 | + | ||
170 | + assert(link); | ||
171 | + assert(link->manager); | ||
172 | + assert(type >= 0 && type < _REQUEST_TYPE_MAX); | ||
173 | + assert(object); | ||
174 | + assert(netlink_handler); | ||
175 | + | ||
176 | + req = new(Request, 1); | ||
177 | + if (!req) { | ||
178 | + if (consume_object) | ||
179 | + request_free_object(type, object); | ||
180 | + return -ENOMEM; | ||
181 | + } | ||
182 | + | ||
183 | + *req = (Request) { | ||
184 | + .link = link, | ||
185 | + .type = type, | ||
186 | + .object = object, | ||
187 | + .consume_object = consume_object, | ||
188 | + .message_counter = message_counter, | ||
189 | + .netlink_handler = netlink_handler, | ||
190 | + }; | ||
191 | + | ||
192 | + link_ref(link); | ||
193 | + | ||
194 | + r = ordered_set_ensure_put(&link->manager->request_queue, NULL, req); | ||
195 | + if (r < 0) | ||
196 | + return r; | ||
197 | + | ||
198 | + if (req->message_counter) | ||
199 | + (*req->message_counter)++; | ||
200 | + | ||
201 | + if (ret) | ||
202 | + *ret = req; | ||
203 | + | ||
204 | + TAKE_PTR(req); | ||
205 | + return 0; | ||
206 | +} | ||
207 | + | ||
208 | +int manager_process_requests(sd_event_source *s, void *userdata) { | ||
209 | + Manager *manager = userdata; | ||
210 | + int r; | ||
211 | + | ||
212 | + assert(manager); | ||
213 | + | ||
214 | + for (;;) { | ||
215 | + bool processed = false; | ||
216 | + Request *req; | ||
217 | + Iterator i; | ||
218 | + ORDERED_SET_FOREACH(req, manager->request_queue, i) { | ||
219 | + switch(req->type) { | ||
220 | + default: | ||
221 | + return -EINVAL; | ||
222 | + } | ||
223 | + if (r < 0) | ||
224 | + link_enter_failed(req->link); | ||
225 | + if (r > 0) { | ||
226 | + ordered_set_remove(manager->request_queue, req); | ||
227 | + request_free(req); | ||
228 | + processed = true; | ||
229 | + } | ||
230 | + } | ||
231 | + | ||
232 | + if (!processed) | ||
233 | + break; | ||
234 | + } | ||
235 | + | ||
236 | + return 0; | ||
237 | +} | ||
238 | diff --git a/src/network/networkd-queue.h b/src/network/networkd-queue.h | ||
239 | new file mode 100644 | ||
240 | index 0000000000..4558ae548f | ||
241 | --- /dev/null | ||
242 | +++ b/src/network/networkd-queue.h | ||
243 | @@ -0,0 +1,42 @@ | ||
244 | +/* SPDX-License-Identifier: LGPL-2.1-or-later */ | ||
245 | +#pragma once | ||
246 | + | ||
247 | +#include "sd-event.h" | ||
248 | + | ||
249 | +#include "networkd-link.h" | ||
250 | + | ||
251 | +typedef struct Request Request; | ||
252 | + | ||
253 | +typedef int (*request_after_configure_handler_t)(Request*, void*); | ||
254 | +typedef void (*request_on_free_handler_t)(Request*); | ||
255 | + | ||
256 | +typedef enum RequestType { | ||
257 | + _REQUEST_TYPE_MAX, | ||
258 | + _REQUEST_TYPE_INVALID = -EINVAL, | ||
259 | +} RequestType; | ||
260 | + | ||
261 | +typedef struct Request { | ||
262 | + Link *link; | ||
263 | + RequestType type; | ||
264 | + bool consume_object; | ||
265 | + void *object; | ||
266 | + void *userdata; | ||
267 | + unsigned *message_counter; | ||
268 | + link_netlink_message_handler_t netlink_handler; | ||
269 | + request_after_configure_handler_t after_configure; | ||
270 | + request_on_free_handler_t on_free; | ||
271 | +} Request; | ||
272 | + | ||
273 | +Request *request_free(Request *req); | ||
274 | +void request_drop(Request *req); | ||
275 | + | ||
276 | +int link_queue_request( | ||
277 | + Link *link, | ||
278 | + RequestType type, | ||
279 | + void *object, | ||
280 | + bool consume_object, | ||
281 | + unsigned *message_counter, | ||
282 | + link_netlink_message_handler_t netlink_handler, | ||
283 | + Request **ret); | ||
284 | + | ||
285 | +int manager_process_requests(sd_event_source *s, void *userdata); | ||
diff --git a/meta/recipes-core/systemd/systemd/network-also-drop-requests-when-link-enters-linger-state.patch b/meta/recipes-core/systemd/systemd/network-also-drop-requests-when-link-enters-linger-state.patch new file mode 100644 index 0000000000..4c402e7e55 --- /dev/null +++ b/meta/recipes-core/systemd/systemd/network-also-drop-requests-when-link-enters-linger-state.patch | |||
@@ -0,0 +1,50 @@ | |||
1 | From 56001f023305ea99329e27141d6e6067596491a9 Mon Sep 17 00:00:00 2001 | ||
2 | From: Yu Watanabe <watanabe.yu+github@gmail.com> | ||
3 | Date: Mon, 17 May 2021 15:32:57 +0900 | ||
4 | Subject: [PATCH] network: also drop requests when link enters linger state | ||
5 | |||
6 | Otherwise, if link is removed, several references to the link in remain | ||
7 | exist in requests. | ||
8 | |||
9 | Upstream-Status: Backport [https://github.com/systemd/systemd-stable/commit/56001f023305ea99329e27141d6e6067596491a9] | ||
10 | Signed-off-by: Ranjitsinh Rathod <ranjitsinh.rathod@kpit.com> | ||
11 | |||
12 | --- | ||
13 | src/network/networkd-link.c | 24 +++++++++++++----------- | ||
14 | 1 file changed, 13 insertions(+), 11 deletions(-) | ||
15 | |||
16 | diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c | ||
17 | index 67d01ac44d..b56c232eca 100644 | ||
18 | --- a/src/network/networkd-link.c | ||
19 | +++ b/src/network/networkd-link.c | ||
20 | @@ -1771,6 +1771,18 @@ static void link_drop_from_master(Link *link, NetDev *netdev) { | ||
21 | link_unref(set_remove(master->slaves, link)); | ||
22 | } | ||
23 | |||
24 | +static void link_drop_requests(Link *link) { | ||
25 | + Request *req; | ||
26 | + Iterator i; | ||
27 | + | ||
28 | + assert(link); | ||
29 | + assert(link->manager); | ||
30 | + | ||
31 | + ORDERED_SET_FOREACH(req, link->manager->request_queue, i) | ||
32 | + if (req->link == link) | ||
33 | + request_drop(req); | ||
34 | +} | ||
35 | + | ||
36 | void link_drop(Link *link) { | ||
37 | if (!link) | ||
38 | return; | ||
39 | @@ -1782,6 +1793,8 @@ void link_drop(Link *link) { | ||
40 | /* Drop all references from other links and manager. Note that async netlink calls may have | ||
41 | * references to the link, and they will be dropped when we receive replies. */ | ||
42 | |||
43 | + link_drop_requests(link); | ||
44 | + | ||
45 | link_free_carrier_maps(link); | ||
46 | |||
47 | if (link->network) { | ||
48 | -- | ||
49 | 2.17.1 | ||
50 | |||
diff --git a/meta/recipes-core/systemd/systemd/network-fix-Link-reference-counter-issue.patch b/meta/recipes-core/systemd/systemd/network-fix-Link-reference-counter-issue.patch new file mode 100644 index 0000000000..a186bb4095 --- /dev/null +++ b/meta/recipes-core/systemd/systemd/network-fix-Link-reference-counter-issue.patch | |||
@@ -0,0 +1,278 @@ | |||
1 | From cc2d7efc5ca09a7de4bec55e80476986839a655c Mon Sep 17 00:00:00 2001 | ||
2 | From: Yu Watanabe <watanabe.yu+github@gmail.com> | ||
3 | Date: Fri, 14 May 2021 15:58:15 +0900 | ||
4 | Subject: [PATCH] network: fix Link reference counter issue | ||
5 | |||
6 | Previously, when link_new() fails, `link_unref()` was called, so, | ||
7 | `Manager::links` may become dirty. | ||
8 | This introduces `link_drop_or_unref()` and it will be called on | ||
9 | failure. | ||
10 | |||
11 | Upstream-Status: Backport [https://github.com/systemd/systemd-stable/commit/cc2d7efc5ca09a7de4bec55e80476986839a655c] | ||
12 | Signed-off-by: Ranjitsinh Rathod <ranjitsinh.rathod@kpit.com> | ||
13 | |||
14 | --- | ||
15 | src/network/networkd-link.c | 240 ++++++++++++++++++------------------ | ||
16 | 1 file changed, 122 insertions(+), 118 deletions(-) | ||
17 | |||
18 | diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c | ||
19 | index b56c232eca..d493afda4c 100644 | ||
20 | --- a/src/network/networkd-link.c | ||
21 | +++ b/src/network/networkd-link.c | ||
22 | @@ -540,109 +540,6 @@ static int link_update_flags(Link *link, | ||
23 | return 0; | ||
24 | } | ||
25 | |||
26 | -static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) { | ||
27 | - _cleanup_(link_unrefp) Link *link = NULL; | ||
28 | - uint16_t type; | ||
29 | - const char *ifname, *kind = NULL; | ||
30 | - int r, ifindex; | ||
31 | - unsigned short iftype; | ||
32 | - | ||
33 | - assert(manager); | ||
34 | - assert(message); | ||
35 | - assert(ret); | ||
36 | - | ||
37 | - /* check for link kind */ | ||
38 | - r = sd_netlink_message_enter_container(message, IFLA_LINKINFO); | ||
39 | - if (r == 0) { | ||
40 | - (void) sd_netlink_message_read_string(message, IFLA_INFO_KIND, &kind); | ||
41 | - r = sd_netlink_message_exit_container(message); | ||
42 | - if (r < 0) | ||
43 | - return r; | ||
44 | - } | ||
45 | - | ||
46 | - r = sd_netlink_message_get_type(message, &type); | ||
47 | - if (r < 0) | ||
48 | - return r; | ||
49 | - else if (type != RTM_NEWLINK) | ||
50 | - return -EINVAL; | ||
51 | - | ||
52 | - r = sd_rtnl_message_link_get_ifindex(message, &ifindex); | ||
53 | - if (r < 0) | ||
54 | - return r; | ||
55 | - else if (ifindex <= 0) | ||
56 | - return -EINVAL; | ||
57 | - | ||
58 | - r = sd_rtnl_message_link_get_type(message, &iftype); | ||
59 | - if (r < 0) | ||
60 | - return r; | ||
61 | - | ||
62 | - r = sd_netlink_message_read_string(message, IFLA_IFNAME, &ifname); | ||
63 | - if (r < 0) | ||
64 | - return r; | ||
65 | - | ||
66 | - link = new(Link, 1); | ||
67 | - if (!link) | ||
68 | - return -ENOMEM; | ||
69 | - | ||
70 | - *link = (Link) { | ||
71 | - .n_ref = 1, | ||
72 | - .manager = manager, | ||
73 | - .state = LINK_STATE_PENDING, | ||
74 | - .ifindex = ifindex, | ||
75 | - .iftype = iftype, | ||
76 | - | ||
77 | - .n_dns = (unsigned) -1, | ||
78 | - .dns_default_route = -1, | ||
79 | - .llmnr = _RESOLVE_SUPPORT_INVALID, | ||
80 | - .mdns = _RESOLVE_SUPPORT_INVALID, | ||
81 | - .dnssec_mode = _DNSSEC_MODE_INVALID, | ||
82 | - .dns_over_tls_mode = _DNS_OVER_TLS_MODE_INVALID, | ||
83 | - }; | ||
84 | - | ||
85 | - link->ifname = strdup(ifname); | ||
86 | - if (!link->ifname) | ||
87 | - return -ENOMEM; | ||
88 | - | ||
89 | - if (kind) { | ||
90 | - link->kind = strdup(kind); | ||
91 | - if (!link->kind) | ||
92 | - return -ENOMEM; | ||
93 | - } | ||
94 | - | ||
95 | - r = sd_netlink_message_read_u32(message, IFLA_MASTER, (uint32_t *)&link->master_ifindex); | ||
96 | - if (r < 0) | ||
97 | - log_link_debug_errno(link, r, "New device has no master, continuing without"); | ||
98 | - | ||
99 | - r = sd_netlink_message_read_ether_addr(message, IFLA_ADDRESS, &link->mac); | ||
100 | - if (r < 0) | ||
101 | - log_link_debug_errno(link, r, "MAC address not found for new device, continuing without"); | ||
102 | - | ||
103 | - if (asprintf(&link->state_file, "/run/systemd/netif/links/%d", link->ifindex) < 0) | ||
104 | - return -ENOMEM; | ||
105 | - | ||
106 | - if (asprintf(&link->lease_file, "/run/systemd/netif/leases/%d", link->ifindex) < 0) | ||
107 | - return -ENOMEM; | ||
108 | - | ||
109 | - if (asprintf(&link->lldp_file, "/run/systemd/netif/lldp/%d", link->ifindex) < 0) | ||
110 | - return -ENOMEM; | ||
111 | - | ||
112 | - r = hashmap_ensure_allocated(&manager->links, NULL); | ||
113 | - if (r < 0) | ||
114 | - return r; | ||
115 | - | ||
116 | - r = hashmap_put(manager->links, INT_TO_PTR(link->ifindex), link); | ||
117 | - if (r < 0) | ||
118 | - return r; | ||
119 | - | ||
120 | - r = link_update_flags(link, message, false); | ||
121 | - if (r < 0) | ||
122 | - return r; | ||
123 | - | ||
124 | - *ret = TAKE_PTR(link); | ||
125 | - | ||
126 | - return 0; | ||
127 | -} | ||
128 | - | ||
129 | void link_ntp_settings_clear(Link *link) { | ||
130 | link->ntp = strv_free(link->ntp); | ||
131 | } | ||
132 | @@ -2030,9 +1927,9 @@ static void link_drop_requests(Link *lin | ||
133 | request_drop(req); | ||
134 | } | ||
135 | |||
136 | -void link_drop(Link *link) { | ||
137 | +Link *link_drop(Link *link) { | ||
138 | if (!link) | ||
139 | - return; | ||
140 | + return NULL; | ||
141 | |||
142 | assert(link->manager); | ||
143 | |||
144 | @@ -2057,7 +1954,7 @@ void link_drop(Link *link) { | ||
145 | |||
146 | /* The following must be called at last. */ | ||
147 | assert_se(hashmap_remove(link->manager->links, INT_TO_PTR(link->ifindex)) == link); | ||
148 | - link_unref(link); | ||
149 | + return link_unref(link); | ||
150 | } | ||
151 | |||
152 | static int link_joined(Link *link) { | ||
153 | @@ -3295,6 +3192,112 @@ ipv4ll_address_fail: | ||
154 | |||
155 | return 0; | ||
156 | } | ||
157 | + | ||
158 | +static Link *link_drop_or_unref(Link *link) { | ||
159 | + if (!link) | ||
160 | + return NULL; | ||
161 | + if (!link->manager) | ||
162 | + return link_unref(link); | ||
163 | + return link_drop(link); | ||
164 | +} | ||
165 | + | ||
166 | +DEFINE_TRIVIAL_CLEANUP_FUNC(Link*, link_drop_or_unref); | ||
167 | + | ||
168 | +static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) { | ||
169 | + _cleanup_(link_drop_or_unrefp) Link *link = NULL; | ||
170 | + uint16_t type; | ||
171 | + _cleanup_free_ char *ifname = NULL, *kind = NULL; | ||
172 | + int r, ifindex; | ||
173 | + unsigned short iftype; | ||
174 | + | ||
175 | + assert(manager); | ||
176 | + assert(message); | ||
177 | + assert(ret); | ||
178 | + | ||
179 | + r = sd_netlink_message_get_type(message, &type); | ||
180 | + if (r < 0) | ||
181 | + return r; | ||
182 | + else if (type != RTM_NEWLINK) | ||
183 | + return -EINVAL; | ||
184 | + | ||
185 | + r = sd_rtnl_message_link_get_ifindex(message, &ifindex); | ||
186 | + if (r < 0) | ||
187 | + return r; | ||
188 | + else if (ifindex <= 0) | ||
189 | + return -EINVAL; | ||
190 | + | ||
191 | + r = sd_rtnl_message_link_get_type(message, &iftype); | ||
192 | + if (r < 0) | ||
193 | + return r; | ||
194 | + | ||
195 | + r = sd_netlink_message_read_string_strdup(message, IFLA_IFNAME, &ifname); | ||
196 | + if (r < 0) | ||
197 | + return r; | ||
198 | + | ||
199 | + /* check for link kind */ | ||
200 | + r = sd_netlink_message_enter_container(message, IFLA_LINKINFO); | ||
201 | + if (r >= 0) { | ||
202 | + (void) sd_netlink_message_read_string_strdup(message, IFLA_INFO_KIND, &kind); | ||
203 | + r = sd_netlink_message_exit_container(message); | ||
204 | + if (r < 0) | ||
205 | + return r; | ||
206 | + } | ||
207 | + | ||
208 | + link = new(Link, 1); | ||
209 | + if (!link) | ||
210 | + return -ENOMEM; | ||
211 | + | ||
212 | + *link = (Link) { | ||
213 | + .n_ref = 1, | ||
214 | + .state = LINK_STATE_PENDING, | ||
215 | + .ifindex = ifindex, | ||
216 | + .iftype = iftype, | ||
217 | + .ifname = TAKE_PTR(ifname), | ||
218 | + .kind = TAKE_PTR(kind), | ||
219 | + | ||
220 | + .n_dns = (unsigned) -1, | ||
221 | + .dns_default_route = -1, | ||
222 | + .llmnr = _RESOLVE_SUPPORT_INVALID, | ||
223 | + .mdns = _RESOLVE_SUPPORT_INVALID, | ||
224 | + .dnssec_mode = _DNSSEC_MODE_INVALID, | ||
225 | + .dns_over_tls_mode = _DNS_OVER_TLS_MODE_INVALID, | ||
226 | + }; | ||
227 | + | ||
228 | + r = hashmap_ensure_allocated(&manager->links, NULL); | ||
229 | + if (r < 0) | ||
230 | + return r; | ||
231 | + | ||
232 | + r = hashmap_put(manager->links, INT_TO_PTR(link->ifindex), link); | ||
233 | + if (r < 0) | ||
234 | + return r; | ||
235 | + | ||
236 | + link->manager = manager; | ||
237 | + | ||
238 | + r = sd_netlink_message_read_u32(message, IFLA_MASTER, (uint32_t*) &link->master_ifindex); | ||
239 | + if (r < 0) | ||
240 | + log_link_debug_errno(link, r, "New device has no master, continuing without"); | ||
241 | + | ||
242 | + r = sd_netlink_message_read_ether_addr(message, IFLA_ADDRESS, &link->mac); | ||
243 | + if (r < 0) | ||
244 | + log_link_debug_errno(link, r, "MAC address not found for new device, continuing without"); | ||
245 | + | ||
246 | + if (asprintf(&link->state_file, "/run/systemd/netif/links/%d", link->ifindex) < 0) | ||
247 | + return -ENOMEM; | ||
248 | + | ||
249 | + if (asprintf(&link->lease_file, "/run/systemd/netif/leases/%d", link->ifindex) < 0) | ||
250 | + return -ENOMEM; | ||
251 | + | ||
252 | + if (asprintf(&link->lldp_file, "/run/systemd/netif/lldp/%d", link->ifindex) < 0) | ||
253 | + return -ENOMEM; | ||
254 | + | ||
255 | + r = link_update_flags(link, message, false); | ||
256 | + if (r < 0) | ||
257 | + return r; | ||
258 | + | ||
259 | + *ret = TAKE_PTR(link); | ||
260 | + | ||
261 | + return 0; | ||
262 | +} | ||
263 | |||
264 | int link_add(Manager *m, sd_netlink_message *message, Link **ret) { | ||
265 | _cleanup_(sd_device_unrefp) sd_device *device = NULL; | ||
266 | |||
267 | --- a/src/network/networkd-link.h 2021-09-02 18:04:16.900542857 +0530 | ||
268 | +++ b/src/network/networkd-link.h 2021-09-02 18:18:56.776571563 +0530 | ||
269 | @@ -175,7 +175,7 @@ DEFINE_TRIVIAL_DESTRUCTOR(link_netlink_d | ||
270 | |||
271 | int link_get(Manager *m, int ifindex, Link **ret); | ||
272 | int link_add(Manager *manager, sd_netlink_message *message, Link **ret); | ||
273 | -void link_drop(Link *link); | ||
274 | +Link *link_drop(Link *link); | ||
275 | |||
276 | int link_down(Link *link, link_netlink_message_handler_t callback); | ||
277 | |||
278 | |||
diff --git a/meta/recipes-core/systemd/systemd/network-merge-link_drop-and-link_detach_from_manager.patch b/meta/recipes-core/systemd/systemd/network-merge-link_drop-and-link_detach_from_manager.patch new file mode 100644 index 0000000000..65bdc611df --- /dev/null +++ b/meta/recipes-core/systemd/systemd/network-merge-link_drop-and-link_detach_from_manager.patch | |||
@@ -0,0 +1,67 @@ | |||
1 | From 63130eb36dc51e4fd50716c585f98ebe456ca7cf Mon Sep 17 00:00:00 2001 | ||
2 | From: Yu Watanabe <watanabe.yu+github@gmail.com> | ||
3 | Date: Mon, 17 May 2021 15:40:15 +0900 | ||
4 | Subject: [PATCH] network: merge link_drop() and link_detach_from_manager() | ||
5 | |||
6 | link_detach_from_manager() is only called by link_drop(). It is not | ||
7 | necessary to split such tiny function. | ||
8 | |||
9 | Upstream-Status: Backport [https://github.com/systemd/systemd-stable/commit/63130eb36dc51e4fd50716c585f98ebe456ca7cf] | ||
10 | Signed-off-by: Ranjitsinh Rathod <ranjitsinh.rathod@kpit.com> | ||
11 | |||
12 | --- | ||
13 | src/network/networkd-link.c | 27 ++++++++++++--------------- | ||
14 | 1 file changed, 12 insertions(+), 15 deletions(-) | ||
15 | |||
16 | diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c | ||
17 | index 9d30e16b0a..67d01ac44d 100644 | ||
18 | --- a/src/network/networkd-link.c | ||
19 | +++ b/src/network/networkd-link.c | ||
20 | @@ -2019,24 +2019,17 @@ static void link_drop_from_master(Link *link, NetDev *netdev) { | ||
21 | link_unref(set_remove(master->slaves, link)); | ||
22 | } | ||
23 | |||
24 | -static void link_detach_from_manager(Link *link) { | ||
25 | - if (!link || !link->manager) | ||
26 | - return; | ||
27 | - | ||
28 | - link_unref(set_remove(link->manager->links_requesting_uuid, link)); | ||
29 | - link_clean(link); | ||
30 | - | ||
31 | - /* The following must be called at last. */ | ||
32 | - assert_se(hashmap_remove(link->manager->links, INT_TO_PTR(link->ifindex)) == link); | ||
33 | - link_unref(link); | ||
34 | -} | ||
35 | - | ||
36 | void link_drop(Link *link) { | ||
37 | - if (!link || link->state == LINK_STATE_LINGER) | ||
38 | + if (!link) | ||
39 | return; | ||
40 | |||
41 | + assert(link->manager); | ||
42 | + | ||
43 | link_set_state(link, LINK_STATE_LINGER); | ||
44 | |||
45 | + /* Drop all references from other links and manager. Note that async netlink calls may have | ||
46 | + * references to the link, and they will be dropped when we receive replies. */ | ||
47 | + | ||
48 | link_free_carrier_maps(link); | ||
49 | |||
50 | if (link->network) { | ||
51 | @@ -2044,10 +2037,14 @@ void link_drop(Link *link) { | ||
52 | link_drop_from_master(link, link->network->bond); | ||
53 | } | ||
54 | |||
55 | - log_link_debug(link, "Link removed"); | ||
56 | + link_unref(set_remove(link->manager->links_requesting_uuid, link)); | ||
57 | |||
58 | (void) unlink(link->state_file); | ||
59 | - link_detach_from_manager(link); | ||
60 | + link_clean(link); | ||
61 | + | ||
62 | + /* The following must be called at last. */ | ||
63 | + assert_se(hashmap_remove(link->manager->links, INT_TO_PTR(link->ifindex)) == link); | ||
64 | + link_unref(link); | ||
65 | } | ||
66 | |||
67 | static int link_joined(Link *link) { | ||
diff --git a/meta/recipes-core/systemd/systemd/rm-rf-optionally-fsync-after-removing-directory-tree.patch b/meta/recipes-core/systemd/systemd/rm-rf-optionally-fsync-after-removing-directory-tree.patch new file mode 100644 index 0000000000..b860da008c --- /dev/null +++ b/meta/recipes-core/systemd/systemd/rm-rf-optionally-fsync-after-removing-directory-tree.patch | |||
@@ -0,0 +1,35 @@ | |||
1 | Backport of the following upstream commit: | ||
2 | From bdfe7ada0d4d66e6d6e65f2822acbb1ec230f9c2 Mon Sep 17 00:00:00 2001 | ||
3 | From: Lennart Poettering <lennart@poettering.net> | ||
4 | Date: Tue, 5 Oct 2021 10:32:56 +0200 | ||
5 | Subject: [PATCH] rm-rf: optionally fsync() after removing directory tree | ||
6 | |||
7 | Upstream-Status: Backport [http://archive.ubuntu.com/ubuntu/pool/main/s/systemd/systemd_245.4-4ubuntu3.15.debian.tar.xz] | ||
8 | Signed-off-by: Purushottam Choudhary <Purushottam.Choudhary@kpit.com> | ||
9 | --- | ||
10 | src/basic/rm-rf.c | 3 +++ | ||
11 | src/basic/rm-rf.h | 1 + | ||
12 | 2 files changed, 4 insertions(+) | ||
13 | |||
14 | --- a/src/basic/rm-rf.c | ||
15 | +++ b/src/basic/rm-rf.c | ||
16 | @@ -161,6 +161,9 @@ | ||
17 | ret = r; | ||
18 | } | ||
19 | |||
20 | + if (FLAGS_SET(flags, REMOVE_SYNCFS) && syncfs(dirfd(d)) < 0 && ret >= 0) | ||
21 | + ret = -errno; | ||
22 | + | ||
23 | return ret; | ||
24 | } | ||
25 | |||
26 | --- a/src/basic/rm-rf.h | ||
27 | +++ b/src/basic/rm-rf.h | ||
28 | @@ -11,6 +11,7 @@ | ||
29 | REMOVE_PHYSICAL = 1 << 2, /* If not set, only removes files on tmpfs, never physical file systems */ | ||
30 | REMOVE_SUBVOLUME = 1 << 3, /* Drop btrfs subvolumes in the tree too */ | ||
31 | REMOVE_MISSING_OK = 1 << 4, /* If the top-level directory is missing, ignore the ENOENT for it */ | ||
32 | + REMOVE_SYNCFS = 1 << 7, /* syncfs() the root of the specified directory after removing everything in it */ | ||
33 | } RemoveFlags; | ||
34 | |||
35 | int rm_rf_children(int fd, RemoveFlags flags, const struct stat *root_dev); | ||
diff --git a/meta/recipes-core/systemd/systemd/rm-rf-refactor-rm-rf-children-split-out-body-of-directory.patch b/meta/recipes-core/systemd/systemd/rm-rf-refactor-rm-rf-children-split-out-body-of-directory.patch new file mode 100644 index 0000000000..f80e6433c6 --- /dev/null +++ b/meta/recipes-core/systemd/systemd/rm-rf-refactor-rm-rf-children-split-out-body-of-directory.patch | |||
@@ -0,0 +1,318 @@ | |||
1 | Backport of the following upstream commit: | ||
2 | From 96906b22417c65d70933976e0ee920c70c9113a4 Mon Sep 17 00:00:00 2001 | ||
3 | From: Lennart Poettering <lennart@poettering.net> | ||
4 | Date: Tue, 26 Jan 2021 16:30:06 +0100 | ||
5 | Subject: [PATCH] rm-rf: refactor rm_rf_children(), split out body of directory | ||
6 | iteration loop | ||
7 | |||
8 | This splits out rm_rf_children_inner() as body of the loop. We can use | ||
9 | that to implement rm_rf_child() for deleting one specific entry in a | ||
10 | directory. | ||
11 | |||
12 | Upstream-Status: Backport [http://archive.ubuntu.com/ubuntu/pool/main/s/systemd/systemd_245.4-4ubuntu3.15.debian.tar.xz] | ||
13 | Signed-off-by: Purushottam Choudhary <Purushottam.Choudhary@kpit.com> | ||
14 | --- | ||
15 | src/basic/rm-rf.c | 223 ++++++++++++++++++++++++++------------------- | ||
16 | src/basic/rm-rf.h | 3 +- | ||
17 | 2 files changed, 131 insertions(+), 95 deletions(-) | ||
18 | |||
19 | --- a/src/basic/rm-rf.c | ||
20 | +++ b/src/basic/rm-rf.c | ||
21 | @@ -19,138 +19,153 @@ | ||
22 | #include "stat-util.h" | ||
23 | #include "string-util.h" | ||
24 | |||
25 | +/* We treat tmpfs/ramfs + cgroupfs as non-physical file sytems. cgroupfs is similar to tmpfs in a way after | ||
26 | + * all: we can create arbitrary directory hierarchies in it, and hence can also use rm_rf() on it to remove | ||
27 | + * those again. */ | ||
28 | static bool is_physical_fs(const struct statfs *sfs) { | ||
29 | return !is_temporary_fs(sfs) && !is_cgroup_fs(sfs); | ||
30 | } | ||
31 | |||
32 | -int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) { | ||
33 | +static int rm_rf_children_inner( | ||
34 | + int fd, | ||
35 | + const char *fname, | ||
36 | + int is_dir, | ||
37 | + RemoveFlags flags, | ||
38 | + const struct stat *root_dev) { | ||
39 | + | ||
40 | + struct stat st; | ||
41 | + int r; | ||
42 | + | ||
43 | + assert(fd >= 0); | ||
44 | + assert(fname); | ||
45 | + | ||
46 | + if (is_dir < 0 || (is_dir > 0 && (root_dev || (flags & REMOVE_SUBVOLUME)))) { | ||
47 | + | ||
48 | + r = fstatat(fd, fname, &st, AT_SYMLINK_NOFOLLOW); | ||
49 | + if (r < 0) | ||
50 | + return r; | ||
51 | + | ||
52 | + is_dir = S_ISDIR(st.st_mode); | ||
53 | + } | ||
54 | + | ||
55 | + if (is_dir) { | ||
56 | + _cleanup_close_ int subdir_fd = -1; | ||
57 | + int q; | ||
58 | + | ||
59 | + /* if root_dev is set, remove subdirectories only if device is same */ | ||
60 | + if (root_dev && st.st_dev != root_dev->st_dev) | ||
61 | + return 0; | ||
62 | + | ||
63 | + /* Stop at mount points */ | ||
64 | + r = fd_is_mount_point(fd, fname, 0); | ||
65 | + if (r < 0) | ||
66 | + return r; | ||
67 | + if (r > 0) | ||
68 | + return 0; | ||
69 | + | ||
70 | + if ((flags & REMOVE_SUBVOLUME) && st.st_ino == 256) { | ||
71 | + | ||
72 | + /* This could be a subvolume, try to remove it */ | ||
73 | + | ||
74 | + r = btrfs_subvol_remove_fd(fd, fname, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA); | ||
75 | + if (r < 0) { | ||
76 | + if (!IN_SET(r, -ENOTTY, -EINVAL)) | ||
77 | + return r; | ||
78 | + | ||
79 | + /* ENOTTY, then it wasn't a btrfs subvolume, continue below. */ | ||
80 | + } else | ||
81 | + /* It was a subvolume, done. */ | ||
82 | + return 1; | ||
83 | + } | ||
84 | + | ||
85 | + subdir_fd = openat(fd, fname, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME); | ||
86 | + if (subdir_fd < 0) | ||
87 | + return -errno; | ||
88 | + | ||
89 | + /* We pass REMOVE_PHYSICAL here, to avoid doing the fstatfs() to check the file system type | ||
90 | + * again for each directory */ | ||
91 | + q = rm_rf_children(TAKE_FD(subdir_fd), flags | REMOVE_PHYSICAL, root_dev); | ||
92 | + | ||
93 | + r = unlinkat(fd, fname, AT_REMOVEDIR); | ||
94 | + if (r < 0) | ||
95 | + return r; | ||
96 | + if (q < 0) | ||
97 | + return q; | ||
98 | + | ||
99 | + return 1; | ||
100 | + | ||
101 | + } else if (!(flags & REMOVE_ONLY_DIRECTORIES)) { | ||
102 | + r = unlinkat(fd, fname, 0); | ||
103 | + if (r < 0) | ||
104 | + return r; | ||
105 | + | ||
106 | + return 1; | ||
107 | + } | ||
108 | + | ||
109 | + return 0; | ||
110 | +} | ||
111 | + | ||
112 | +int rm_rf_children( | ||
113 | + int fd, | ||
114 | + RemoveFlags flags, | ||
115 | + const struct stat *root_dev) { | ||
116 | + | ||
117 | _cleanup_closedir_ DIR *d = NULL; | ||
118 | struct dirent *de; | ||
119 | int ret = 0, r; | ||
120 | - struct statfs sfs; | ||
121 | |||
122 | assert(fd >= 0); | ||
123 | |||
124 | /* This returns the first error we run into, but nevertheless tries to go on. This closes the passed | ||
125 | - * fd, in all cases, including on failure.. */ | ||
126 | + * fd, in all cases, including on failure. */ | ||
127 | + | ||
128 | + d = fdopendir(fd); | ||
129 | + if (!d) { | ||
130 | + safe_close(fd); | ||
131 | + return -errno; | ||
132 | + } | ||
133 | |||
134 | if (!(flags & REMOVE_PHYSICAL)) { | ||
135 | + struct statfs sfs; | ||
136 | |||
137 | - r = fstatfs(fd, &sfs); | ||
138 | - if (r < 0) { | ||
139 | - safe_close(fd); | ||
140 | + if (fstatfs(dirfd(d), &sfs) < 0) | ||
141 | return -errno; | ||
142 | } | ||
143 | |||
144 | if (is_physical_fs(&sfs)) { | ||
145 | - /* We refuse to clean physical file systems with this call, | ||
146 | - * unless explicitly requested. This is extra paranoia just | ||
147 | - * to be sure we never ever remove non-state data. */ | ||
148 | + /* We refuse to clean physical file systems with this call, unless explicitly | ||
149 | + * requested. This is extra paranoia just to be sure we never ever remove non-state | ||
150 | + * data. */ | ||
151 | + | ||
152 | _cleanup_free_ char *path = NULL; | ||
153 | |||
154 | (void) fd_get_path(fd, &path); | ||
155 | - log_error("Attempted to remove disk file system under \"%s\", and we can't allow that.", | ||
156 | - strna(path)); | ||
157 | - | ||
158 | - safe_close(fd); | ||
159 | - return -EPERM; | ||
160 | + return log_error_errno(SYNTHETIC_ERRNO(EPERM), | ||
161 | + "Attempted to remove disk file system under \"%s\", and we can't allow that.", | ||
162 | + strna(path)); | ||
163 | } | ||
164 | } | ||
165 | |||
166 | - d = fdopendir(fd); | ||
167 | - if (!d) { | ||
168 | - safe_close(fd); | ||
169 | - return errno == ENOENT ? 0 : -errno; | ||
170 | - } | ||
171 | - | ||
172 | FOREACH_DIRENT_ALL(de, d, return -errno) { | ||
173 | - bool is_dir; | ||
174 | - struct stat st; | ||
175 | + int is_dir; | ||
176 | |||
177 | if (dot_or_dot_dot(de->d_name)) | ||
178 | continue; | ||
179 | |||
180 | - if (de->d_type == DT_UNKNOWN || | ||
181 | - (de->d_type == DT_DIR && (root_dev || (flags & REMOVE_SUBVOLUME)))) { | ||
182 | - if (fstatat(fd, de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) { | ||
183 | - if (ret == 0 && errno != ENOENT) | ||
184 | - ret = -errno; | ||
185 | - continue; | ||
186 | - } | ||
187 | - | ||
188 | - is_dir = S_ISDIR(st.st_mode); | ||
189 | - } else | ||
190 | - is_dir = de->d_type == DT_DIR; | ||
191 | - | ||
192 | - if (is_dir) { | ||
193 | - _cleanup_close_ int subdir_fd = -1; | ||
194 | - | ||
195 | - /* if root_dev is set, remove subdirectories only if device is same */ | ||
196 | - if (root_dev && st.st_dev != root_dev->st_dev) | ||
197 | - continue; | ||
198 | - | ||
199 | - subdir_fd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME); | ||
200 | - if (subdir_fd < 0) { | ||
201 | - if (ret == 0 && errno != ENOENT) | ||
202 | - ret = -errno; | ||
203 | - continue; | ||
204 | - } | ||
205 | - | ||
206 | - /* Stop at mount points */ | ||
207 | - r = fd_is_mount_point(fd, de->d_name, 0); | ||
208 | - if (r < 0) { | ||
209 | - if (ret == 0 && r != -ENOENT) | ||
210 | - ret = r; | ||
211 | - | ||
212 | - continue; | ||
213 | - } | ||
214 | - if (r > 0) | ||
215 | - continue; | ||
216 | - | ||
217 | - if ((flags & REMOVE_SUBVOLUME) && st.st_ino == 256) { | ||
218 | - | ||
219 | - /* This could be a subvolume, try to remove it */ | ||
220 | - | ||
221 | - r = btrfs_subvol_remove_fd(fd, de->d_name, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA); | ||
222 | - if (r < 0) { | ||
223 | - if (!IN_SET(r, -ENOTTY, -EINVAL)) { | ||
224 | - if (ret == 0) | ||
225 | - ret = r; | ||
226 | - | ||
227 | - continue; | ||
228 | - } | ||
229 | - | ||
230 | - /* ENOTTY, then it wasn't a btrfs subvolume, continue below. */ | ||
231 | - } else | ||
232 | - /* It was a subvolume, continue. */ | ||
233 | - continue; | ||
234 | - } | ||
235 | - | ||
236 | - /* We pass REMOVE_PHYSICAL here, to avoid doing the fstatfs() to check the file | ||
237 | - * system type again for each directory */ | ||
238 | - r = rm_rf_children(TAKE_FD(subdir_fd), flags | REMOVE_PHYSICAL, root_dev); | ||
239 | - if (r < 0 && ret == 0) | ||
240 | - ret = r; | ||
241 | - | ||
242 | - if (unlinkat(fd, de->d_name, AT_REMOVEDIR) < 0) { | ||
243 | - if (ret == 0 && errno != ENOENT) | ||
244 | - ret = -errno; | ||
245 | - } | ||
246 | - | ||
247 | - } else if (!(flags & REMOVE_ONLY_DIRECTORIES)) { | ||
248 | - | ||
249 | - if (unlinkat(fd, de->d_name, 0) < 0) { | ||
250 | - if (ret == 0 && errno != ENOENT) | ||
251 | - ret = -errno; | ||
252 | - } | ||
253 | - } | ||
254 | + is_dir = | ||
255 | + de->d_type == DT_UNKNOWN ? -1 : | ||
256 | + de->d_type == DT_DIR; | ||
257 | + | ||
258 | + r = rm_rf_children_inner(dirfd(d), de->d_name, is_dir, flags, root_dev); | ||
259 | + if (r < 0 && r != -ENOENT && ret == 0) | ||
260 | + ret = r; | ||
261 | } | ||
262 | + | ||
263 | return ret; | ||
264 | } | ||
265 | |||
266 | int rm_rf(const char *path, RemoveFlags flags) { | ||
267 | int fd, r; | ||
268 | - struct statfs s; | ||
269 | |||
270 | assert(path); | ||
271 | |||
272 | @@ -195,9 +210,10 @@ | ||
273 | if (FLAGS_SET(flags, REMOVE_ROOT)) { | ||
274 | |||
275 | if (!FLAGS_SET(flags, REMOVE_PHYSICAL)) { | ||
276 | + struct statfs s; | ||
277 | + | ||
278 | if (statfs(path, &s) < 0) | ||
279 | return -errno; | ||
280 | - | ||
281 | if (is_physical_fs(&s)) | ||
282 | return log_error_errno(SYNTHETIC_ERRNO(EPERM), | ||
283 | "Attempted to remove files from a disk file system under \"%s\", refusing.", | ||
284 | @@ -225,3 +241,22 @@ | ||
285 | |||
286 | return r; | ||
287 | } | ||
288 | + | ||
289 | +int rm_rf_child(int fd, const char *name, RemoveFlags flags) { | ||
290 | + | ||
291 | + /* Removes one specific child of the specified directory */ | ||
292 | + | ||
293 | + if (fd < 0) | ||
294 | + return -EBADF; | ||
295 | + | ||
296 | + if (!filename_is_valid(name)) | ||
297 | + return -EINVAL; | ||
298 | + | ||
299 | + if ((flags & (REMOVE_ROOT|REMOVE_MISSING_OK)) != 0) /* Doesn't really make sense here, we are not supposed to remove 'fd' anyway */ | ||
300 | + return -EINVAL; | ||
301 | + | ||
302 | + if (FLAGS_SET(flags, REMOVE_ONLY_DIRECTORIES|REMOVE_SUBVOLUME)) | ||
303 | + return -EINVAL; | ||
304 | + | ||
305 | + return rm_rf_children_inner(fd, name, -1, flags, NULL); | ||
306 | +} | ||
307 | --- a/src/basic/rm-rf.h | ||
308 | +++ b/src/basic/rm-rf.h | ||
309 | @@ -13,7 +13,8 @@ | ||
310 | REMOVE_MISSING_OK = 1 << 4, /* If the top-level directory is missing, ignore the ENOENT for it */ | ||
311 | } RemoveFlags; | ||
312 | |||
313 | -int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev); | ||
314 | +int rm_rf_children(int fd, RemoveFlags flags, const struct stat *root_dev); | ||
315 | +int rm_rf_child(int fd, const char *name, RemoveFlags flags); | ||
316 | int rm_rf(const char *path, RemoveFlags flags); | ||
317 | |||
318 | /* Useful for usage with _cleanup_(), destroys a directory and frees the pointer */ | ||
diff --git a/meta/recipes-core/systemd/systemd/systemd-pager.sh b/meta/recipes-core/systemd/systemd/systemd-pager.sh new file mode 100644 index 0000000000..86e3e0ab78 --- /dev/null +++ b/meta/recipes-core/systemd/systemd/systemd-pager.sh | |||
@@ -0,0 +1,7 @@ | |||
1 | # Systemd expect a color capable pager, however the less provided | ||
2 | # by busybox is not. This make many interaction with systemd pretty | ||
3 | # annoying. As a workaround we disable the systemd pager if less | ||
4 | # is not the GNU version. | ||
5 | if ! less -V > /dev/null 2>&1 ; then | ||
6 | export SYSTEMD_PAGER= | ||
7 | fi | ||