Merge ~enr0n/ubuntu/+source/systemd:ubuntu-kinetic-sru into ~ubuntu-core-dev/ubuntu/+source/systemd:ubuntu-kinetic

Proposed by Nick Rosbrook
Status: Merged
Merged at revision: 74ae8a98d5e803a6513ad3bd0ccad4e91b235397
Proposed branch: ~enr0n/ubuntu/+source/systemd:ubuntu-kinetic-sru
Merge into: ~ubuntu-core-dev/ubuntu/+source/systemd:ubuntu-kinetic
Diff against target: 983 lines (+913/-0)
11 files modified
debian/changelog (+31/-0)
debian/patches/CVE-2022-4415.patch (+380/-0)
debian/patches/CVE-2022-45873.patch (+115/-0)
debian/patches/backport-for-CVE-2022-45873.patch (+45/-0)
debian/patches/lp2002445/sd-netlink-add-a-test-for-rtnl_set_link_name.patch (+66/-0)
debian/patches/lp2002445/sd-netlink-do-not-swap-old-name-and-alternative-name.patch (+54/-0)
debian/patches/lp2002445/sd-netlink-restore-altname-on-error-in-rtnl_set_link_name.patch (+64/-0)
debian/patches/lp2002445/udev-attempt-device-rename-even-if-interface-is-up.patch (+61/-0)
debian/patches/lp2002445/udev-net-allow-new-link-name-as-an-altname-before-renamin.patch (+34/-0)
debian/patches/lp2004478-network-dhcp4-accept-local-subnet-routes-from-DHCP.patch (+54/-0)
debian/patches/series (+9/-0)
Reviewer Review Type Date Requested Status
Lukas Märdian Approve
Review via email: mp+438555@code.launchpad.net

Description of the change

PPA: https://launchpad.net/~enr0n/+archive/ubuntu/systemd-251/+packages?field.name_filter=systemd&field.status_filter=published

These autopkgtest results are from a previous build, i.e. before rebasing on the security update. The networkd-test.py failure is already present and will not be considered a regression. The unit-tests failure in armhf is fixed in my latest build, though I did not re-trigger the autopkgtest because it was a known issue, and I just forgot to include the fix in the tested build.

systemd 251.4-1ubuntu7.1~ppa3 (arm64) -- Fail: https://autopkgtest.ubuntu.com/results/autopkgtest-kinetic-enr0n-systemd-251/kinetic/arm64/s/systemd/20230302_125651_41ba8@/log.gz
systemd 251.4-1ubuntu7.1~ppa3 (armhf) -- Fail: https://autopkgtest.ubuntu.com/results/autopkgtest-kinetic-enr0n-systemd-251/kinetic/armhf/s/systemd/20230302_052203_41ba8@/log.gz
systemd 251.4-1ubuntu7.1~ppa3 (ppc64el) -- Fail: https://autopkgtest.ubuntu.com/results/autopkgtest-kinetic-enr0n-systemd-251/kinetic/ppc64el/s/systemd/20230301_230404_11ba2@/log.gz
systemd 251.4-1ubuntu7.1~ppa3 (s390x) -- Fail: https://autopkgtest.ubuntu.com/results/autopkgtest-kinetic-enr0n-systemd-251/kinetic/s390x/s/systemd/20230302_003917_11ba2@/log.gz
systemd 251.4-1ubuntu7.1~ppa4 (amd64) -- Fail: https://autopkgtest.ubuntu.com/results/autopkgtest-kinetic-enr0n-systemd-251/kinetic/amd64/s/systemd/20230303_021808_57da3@/log.gz

To post a comment you must log in.
Revision history for this message
Lukas Märdian (slyon) wrote :

Thanks for the explanation about the test failures. Apparently networkd-test.py regressed in release, which is bad but seems unrelated to the systemd package:

"There is an autopkgtest failure currently in kinetic (not considered a regression) that seems to be caused by a kernel change. I am not exactly sure what change broke the test, but if I run the test in a fresh kinetic install (nothing from -updates installed yet), the test passes. But if I install just the new kernel from -updates, the test fails." -- enr0n

Do we already have a tracking bug report about that ^ issue? Could you please reference it here and escalate it to the corresponding (Kernel?) team? Having systemd autopkgtests failing in a stable series is not a good position to be in and we should try to get it fixed soon (by the corresponding team).

Your changes/patches to systemd packaging itself LGTM!

review: Approve
Revision history for this message
Lukas Märdian (slyon) wrote :
Revision history for this message
Nick Rosbrook (enr0n) wrote :

I have opened bug 2009859 to track the issue.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/debian/changelog b/debian/changelog
2index c7ddcfc..2fe2841 100644
3--- a/debian/changelog
4+++ b/debian/changelog
5@@ -1,3 +1,34 @@
6+systemd (251.4-1ubuntu7.2) kinetic; urgency=medium
7+
8+ * network/dhcp4: accept local subnet routes from DHCP (LP: #2004478)
9+ File: debian/patches/lp2004478-network-dhcp4-accept-local-subnet-routes-from-DHCP.patch
10+ https://git.launchpad.net/~ubuntu-core-dev/ubuntu/+source/systemd/commit/?id=751bac59b405025964d76c4ef8e0603457a605af
11+ * udev: avoid NIC renaming race with kernel (LP: #2002445)
12+ Files:
13+ - debian/patches/lp2002445/sd-netlink-add-a-test-for-rtnl_set_link_name.patch
14+ - debian/patches/lp2002445/sd-netlink-do-not-swap-old-name-and-alternative-name.patch
15+ - debian/patches/lp2002445/sd-netlink-restore-altname-on-error-in-rtnl_set_link_name.patch
16+ - debian/patches/lp2002445/udev-attempt-device-rename-even-if-interface-is-up.patch
17+ - debian/patches/lp2002445/udev-net-allow-new-link-name-as-an-altname-before-renamin.patch
18+ https://git.launchpad.net/~ubuntu-core-dev/ubuntu/+source/systemd/commit/?id=ffb1e85fdd3f0fe9b158b28a95cfa6d241fcbe70
19+
20+ -- Nick Rosbrook <nick.rosbrook@canonical.com> Wed, 08 Mar 2023 12:07:55 -0500
21+
22+systemd (251.4-1ubuntu7.1) kinetic-security; urgency=medium
23+
24+ * SECURITY UPDATE: information leak vulnerability in systemd-coredump
25+ - debian/patches/CVE-2022-4415.patch: do not allow user to access
26+ coredumps with changed uid/gid/capabilities
27+ - CVE-2022-4415
28+ * SECURITY UPDATE: DoS vulnerability in systemd-coredump
29+ - debian/patches/backport-for-CVE-2022-45873.patch: allow
30+ json_variant_dump() to return an error
31+ - debian/patches/CVE-2022-45873.patch: avoid deadlock when passing
32+ processed backtrace data
33+ - CVE-2022-45873
34+
35+ -- Nishit Majithia <nishit.majithia@canonical.com> Thu, 02 Mar 2023 18:28:02 +0530
36+
37 systemd (251.4-1ubuntu7) kinetic; urgency=medium
38
39 [ Nick Rosbrook ]
40diff --git a/debian/patches/CVE-2022-4415.patch b/debian/patches/CVE-2022-4415.patch
41new file mode 100644
42index 0000000..cc12be9
43--- /dev/null
44+++ b/debian/patches/CVE-2022-4415.patch
45@@ -0,0 +1,380 @@
46+ Origin: backport, https://github.com/systemd/systemd-stable/commit/efca5283dc791a07171f80eef84e14fdb58fad57
47+
48+From efca5283dc791a07171f80eef84e14fdb58fad57 Mon Sep 17 00:00:00 2001
49+From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
50+Date: Mon, 28 Nov 2022 12:12:55 +0100
51+Subject: [PATCH] coredump: do not allow user to access coredumps with changed
52+ uid/gid/capabilities
53+
54+When the user starts a program which elevates its permissions via setuid,
55+setgid, or capabilities set on the file, it may access additional information
56+which would then be visible in the coredump. We shouldn't make the the coredump
57+visible to the user in such cases.
58+
59+Reported-by: Matthias Gerstner <mgerstner@suse.de>
60+
61+This reads the /proc/<pid>/auxv file and attaches it to the process metadata as
62+PROC_AUXV. Before the coredump is submitted, it is parsed and if either
63+at_secure was set (which the kernel will do for processes that are setuid,
64+setgid, or setcap), or if the effective uid/gid don't match uid/gid, the file
65+is not made accessible to the user. If we can't access this data, we assume the
66+file should not be made accessible either. In principle we could also access
67+the auxv data from a note in the core file, but that is much more complex and
68+it seems better to use the stand-alone file that is provided by the kernel.
69+
70+Attaching auxv is both convient for this patch (because this way it's passed
71+between the stages along with other fields), but I think it makes sense to save
72+it in general.
73+
74+We use the information early in the core file to figure out if the program was
75+32-bit or 64-bit and its endianness. This way we don't need heuristics to guess
76+whether the format of the auxv structure. This test might reject some cases on
77+fringe architecutes. But the impact would be limited: we just won't grant the
78+user permissions to view the coredump file. If people report that we're missing
79+some cases, we can always enhance this to support more architectures.
80+
81+I tested auxv parsing on amd64, 32-bit program on amd64, arm64, arm32, and
82+ppc64el, but not the whole coredump handling.
83+
84+(cherry picked from commit 3e4d0f6cf99f8677edd6a237382a65bfe758de03)
85+(cherry picked from commit 9b75a3d0502d6741c8ecb7175794345f8eb3827c)
86+---
87+ src/basic/io-util.h | 9 ++
88+ src/coredump/coredump.c | 196 +++++++++++++++++++++++++++++++++++++---
89+ 2 files changed, 192 insertions(+), 13 deletions(-)
90+
91+--- systemd-251.4.orig/src/basic/io-util.h
92++++ systemd-251.4/src/basic/io-util.h
93+@@ -91,7 +91,16 @@ struct iovec_wrapper *iovw_new(void);
94+ struct iovec_wrapper *iovw_free(struct iovec_wrapper *iovw);
95+ struct iovec_wrapper *iovw_free_free(struct iovec_wrapper *iovw);
96+ void iovw_free_contents(struct iovec_wrapper *iovw, bool free_vectors);
97++
98+ int iovw_put(struct iovec_wrapper *iovw, void *data, size_t len);
99++static inline int iovw_consume(struct iovec_wrapper *iovw, void *data, size_t len) {
100++ /* Move data into iovw or free on error */
101++ int r = iovw_put(iovw, data, len);
102++ if (r < 0)
103++ free(data);
104++ return r;
105++}
106++
107+ int iovw_put_string_field(struct iovec_wrapper *iovw, const char *field, const char *value);
108+ int iovw_put_string_field_free(struct iovec_wrapper *iovw, const char *field, char *value);
109+ void iovw_rebase(struct iovec_wrapper *iovw, char *old, char *new);
110+--- systemd-251.4.orig/src/coredump/coredump.c
111++++ systemd-251.4/src/coredump/coredump.c
112+@@ -4,6 +4,7 @@
113+ #include <stdio.h>
114+ #include <sys/prctl.h>
115+ #include <sys/statvfs.h>
116++#include <sys/auxv.h>
117+ #include <sys/xattr.h>
118+ #include <unistd.h>
119+
120+@@ -105,6 +106,7 @@ enum {
121+
122+ META_EXE = _META_MANDATORY_MAX,
123+ META_UNIT,
124++ META_PROC_AUXV,
125+ _META_MAX
126+ };
127+
128+@@ -119,10 +121,12 @@ static const char * const meta_field_nam
129+ [META_COMM] = "COREDUMP_COMM=",
130+ [META_EXE] = "COREDUMP_EXE=",
131+ [META_UNIT] = "COREDUMP_UNIT=",
132++ [META_PROC_AUXV] = "COREDUMP_PROC_AUXV=",
133+ };
134+
135+ typedef struct Context {
136+ const char *meta[_META_MAX];
137++ size_t meta_size[_META_MAX];
138+ pid_t pid;
139+ bool is_pid1;
140+ bool is_journald;
141+@@ -184,13 +188,16 @@ static uint64_t storage_size_max(void) {
142+ return 0;
143+ }
144+
145+-static int fix_acl(int fd, uid_t uid) {
146++static int fix_acl(int fd, uid_t uid, bool allow_user) {
147++ assert(fd >= 0);
148++ assert(uid_is_valid(uid));
149+
150+ #if HAVE_ACL
151+ int r;
152+
153+- assert(fd >= 0);
154+- assert(uid_is_valid(uid));
155++ /* We don't allow users to read coredumps if the uid or capabilities were changed. */
156++ if (!allow_user)
157++ return 0;
158+
159+ if (uid_is_system(uid) || uid_is_dynamic(uid) || uid == UID_NOBODY)
160+ return 0;
161+@@ -250,7 +257,8 @@ static int fix_permissions(
162+ const char *filename,
163+ const char *target,
164+ const Context *context,
165+- uid_t uid) {
166++ uid_t uid,
167++ bool allow_user) {
168+
169+ int r;
170+
171+@@ -260,7 +268,7 @@ static int fix_permissions(
172+
173+ /* Ignore errors on these */
174+ (void) fchmod(fd, 0640);
175+- (void) fix_acl(fd, uid);
176++ (void) fix_acl(fd, uid, allow_user);
177+ (void) fix_xattr(fd, context);
178+
179+ r = fsync_full(fd);
180+@@ -330,6 +338,153 @@ static int make_filename(const Context *
181+ return 0;
182+ }
183+
184++static int parse_auxv64(
185++ const uint64_t *auxv,
186++ size_t size_bytes,
187++ int *at_secure,
188++ uid_t *uid,
189++ uid_t *euid,
190++ gid_t *gid,
191++ gid_t *egid) {
192++
193++ assert(auxv || size_bytes == 0);
194++
195++ if (size_bytes % (2 * sizeof(uint64_t)) != 0)
196++ return log_warning_errno(SYNTHETIC_ERRNO(EIO), "Incomplete auxv structure (%zu bytes).", size_bytes);
197++
198++ size_t words = size_bytes / sizeof(uint64_t);
199++
200++ /* Note that we set output variables even on error. */
201++
202++ for (size_t i = 0; i + 1 < words; i += 2)
203++ switch (auxv[i]) {
204++ case AT_SECURE:
205++ *at_secure = auxv[i + 1] != 0;
206++ break;
207++ case AT_UID:
208++ *uid = auxv[i + 1];
209++ break;
210++ case AT_EUID:
211++ *euid = auxv[i + 1];
212++ break;
213++ case AT_GID:
214++ *gid = auxv[i + 1];
215++ break;
216++ case AT_EGID:
217++ *egid = auxv[i + 1];
218++ break;
219++ case AT_NULL:
220++ if (auxv[i + 1] != 0)
221++ goto error;
222++ return 0;
223++ }
224++ error:
225++ return log_warning_errno(SYNTHETIC_ERRNO(ENODATA),
226++ "AT_NULL terminator not found, cannot parse auxv structure.");
227++}
228++
229++static int parse_auxv32(
230++ const uint32_t *auxv,
231++ size_t size_bytes,
232++ int *at_secure,
233++ uid_t *uid,
234++ uid_t *euid,
235++ gid_t *gid,
236++ gid_t *egid) {
237++
238++ assert(auxv || size_bytes == 0);
239++
240++ size_t words = size_bytes / sizeof(uint32_t);
241++
242++ if (size_bytes % (2 * sizeof(uint32_t)) != 0)
243++ return log_warning_errno(SYNTHETIC_ERRNO(EIO), "Incomplete auxv structure (%zu bytes).", size_bytes);
244++
245++ /* Note that we set output variables even on error. */
246++
247++ for (size_t i = 0; i + 1 < words; i += 2)
248++ switch (auxv[i]) {
249++ case AT_SECURE:
250++ *at_secure = auxv[i + 1] != 0;
251++ break;
252++ case AT_UID:
253++ *uid = auxv[i + 1];
254++ break;
255++ case AT_EUID:
256++ *euid = auxv[i + 1];
257++ break;
258++ case AT_GID:
259++ *gid = auxv[i + 1];
260++ break;
261++ case AT_EGID:
262++ *egid = auxv[i + 1];
263++ break;
264++ case AT_NULL:
265++ if (auxv[i + 1] != 0)
266++ goto error;
267++ return 0;
268++ }
269++ error:
270++ return log_warning_errno(SYNTHETIC_ERRNO(ENODATA),
271++ "AT_NULL terminator not found, cannot parse auxv structure.");
272++}
273++
274++static int grant_user_access(int core_fd, const Context *context) {
275++ int at_secure = -1;
276++ uid_t uid = UID_INVALID, euid = UID_INVALID;
277++ uid_t gid = GID_INVALID, egid = GID_INVALID;
278++ int r;
279++
280++ assert(core_fd >= 0);
281++ assert(context);
282++
283++ if (!context->meta[META_PROC_AUXV])
284++ return log_warning_errno(SYNTHETIC_ERRNO(ENODATA), "No auxv data, not adjusting permissions.");
285++
286++ uint8_t elf[EI_NIDENT];
287++ errno = 0;
288++ if (pread(core_fd, &elf, sizeof(elf), 0) != sizeof(elf))
289++ return log_warning_errno(errno_or_else(EIO),
290++ "Failed to pread from coredump fd: %s", errno != 0 ? strerror_safe(errno) : "Unexpected EOF");
291++
292++ if (elf[EI_MAG0] != ELFMAG0 ||
293++ elf[EI_MAG1] != ELFMAG1 ||
294++ elf[EI_MAG2] != ELFMAG2 ||
295++ elf[EI_MAG3] != ELFMAG3 ||
296++ elf[EI_VERSION] != EV_CURRENT)
297++ return log_info_errno(SYNTHETIC_ERRNO(EUCLEAN),
298++ "Core file does not have ELF header, not adjusting permissions.");
299++ if (!IN_SET(elf[EI_CLASS], ELFCLASS32, ELFCLASS64) ||
300++ !IN_SET(elf[EI_DATA], ELFDATA2LSB, ELFDATA2MSB))
301++ return log_info_errno(SYNTHETIC_ERRNO(EUCLEAN),
302++ "Core file has strange ELF class, not adjusting permissions.");
303++
304++ if ((elf[EI_DATA] == ELFDATA2LSB) != (__BYTE_ORDER == __LITTLE_ENDIAN))
305++ return log_info_errno(SYNTHETIC_ERRNO(EUCLEAN),
306++ "Core file has non-native endianness, not adjusting permissions.");
307++
308++ if (elf[EI_CLASS] == ELFCLASS64)
309++ r = parse_auxv64((const uint64_t*) context->meta[META_PROC_AUXV],
310++ context->meta_size[META_PROC_AUXV],
311++ &at_secure, &uid, &euid, &gid, &egid);
312++ else
313++ r = parse_auxv32((const uint32_t*) context->meta[META_PROC_AUXV],
314++ context->meta_size[META_PROC_AUXV],
315++ &at_secure, &uid, &euid, &gid, &egid);
316++ if (r < 0)
317++ return r;
318++
319++ /* We allow access if we got all the data and at_secure is not set and
320++ * the uid/gid matches euid/egid. */
321++ bool ret =
322++ at_secure == 0 &&
323++ uid != UID_INVALID && euid != UID_INVALID && uid == euid &&
324++ gid != GID_INVALID && egid != GID_INVALID && gid == egid;
325++ log_debug("Will %s access (uid="UID_FMT " euid="UID_FMT " gid="GID_FMT " egid="GID_FMT " at_secure=%s)",
326++ ret ? "permit" : "restrict",
327++ uid, euid, gid, egid, yes_no(at_secure));
328++ return ret;
329++}
330++
331+ static int save_external_coredump(
332+ const Context *context,
333+ int input_fd,
334+@@ -452,6 +607,8 @@ static int save_external_coredump(
335+ context->meta[META_ARGV_PID], context->meta[META_COMM]);
336+ truncated = r == 1;
337+
338++ bool allow_user = grant_user_access(fd, context) > 0;
339++
340+ #if HAVE_COMPRESSION
341+ if (arg_compress) {
342+ _cleanup_(unlink_and_freep) char *tmp_compressed = NULL;
343+@@ -489,7 +646,7 @@ static int save_external_coredump(
344+ uncompressed_size += partial_uncompressed_size;
345+ }
346+
347+- r = fix_permissions(fd_compressed, tmp_compressed, fn_compressed, context, uid);
348++ r = fix_permissions(fd_compressed, tmp_compressed, fn_compressed, context, uid, allow_user);
349+ if (r < 0)
350+ return r;
351+
352+@@ -516,7 +673,7 @@ static int save_external_coredump(
353+ "SIZE_LIMIT=%"PRIu64, max_size,
354+ "MESSAGE_ID=" SD_MESSAGE_TRUNCATED_CORE_STR);
355+
356+- r = fix_permissions(fd, tmp, fn, context, uid);
357++ r = fix_permissions(fd, tmp, fn, context, uid, allow_user);
358+ if (r < 0)
359+ return log_error_errno(r, "Failed to fix permissions and finalize coredump %s into %s: %m", coredump_tmpfile_name(tmp), fn);
360+
361+@@ -764,7 +921,7 @@ static int change_uid_gid(const Context
362+ }
363+
364+ static int submit_coredump(
365+- Context *context,
366++ const Context *context,
367+ struct iovec_wrapper *iovw,
368+ int input_fd) {
369+
370+@@ -925,16 +1082,15 @@ static int save_context(Context *context
371+ struct iovec *iovec = iovw->iovec + n;
372+
373+ for (size_t i = 0; i < ELEMENTSOF(meta_field_names); i++) {
374+- char *p;
375+-
376+ /* Note that these strings are NUL terminated, because we made sure that a
377+ * trailing NUL byte is in the buffer, though not included in the iov_len
378+ * count (see process_socket() and gather_pid_metadata_*()) */
379+ assert(((char*) iovec->iov_base)[iovec->iov_len] == 0);
380+
381+- p = startswith(iovec->iov_base, meta_field_names[i]);
382++ const char *p = startswith(iovec->iov_base, meta_field_names[i]);
383+ if (p) {
384+ context->meta[i] = p;
385++ context->meta_size[i] = iovec->iov_len - strlen(meta_field_names[i]);
386+ count++;
387+ break;
388+ }
389+@@ -1176,6 +1332,7 @@ static int gather_pid_metadata(struct io
390+ uid_t owner_uid;
391+ pid_t pid;
392+ char *t;
393++ size_t size;
394+ const char *p;
395+ int r;
396+
397+@@ -1240,13 +1397,26 @@ static int gather_pid_metadata(struct io
398+ (void) iovw_put_string_field_free(iovw, "COREDUMP_PROC_LIMITS=", t);
399+
400+ p = procfs_file_alloca(pid, "cgroup");
401+- if (read_full_virtual_file(p, &t, NULL) >=0)
402++ if (read_full_virtual_file(p, &t, NULL) >= 0)
403+ (void) iovw_put_string_field_free(iovw, "COREDUMP_PROC_CGROUP=", t);
404+
405+ p = procfs_file_alloca(pid, "mountinfo");
406+- if (read_full_virtual_file(p, &t, NULL) >=0)
407++ if (read_full_virtual_file(p, &t, NULL) >= 0)
408+ (void) iovw_put_string_field_free(iovw, "COREDUMP_PROC_MOUNTINFO=", t);
409+
410++ /* We attach /proc/auxv here. ELF coredumps also contain a note for this (NT_AUXV), see elf(5). */
411++ p = procfs_file_alloca(pid, "auxv");
412++ if (read_full_virtual_file(p, &t, &size) >= 0) {
413++ char *buf = malloc(strlen("COREDUMP_PROC_AUXV=") + size + 1);
414++ if (buf) {
415++ /* Add a dummy terminator to make save_context() happy. */
416++ *((uint8_t*) mempcpy(stpcpy(buf, "COREDUMP_PROC_AUXV="), t, size)) = '\0';
417++ (void) iovw_consume(iovw, buf, size + strlen("COREDUMP_PROC_AUXV="));
418++ }
419++
420++ free(t);
421++ }
422++
423+ if (get_process_cwd(pid, &t) >= 0)
424+ (void) iovw_put_string_field_free(iovw, "COREDUMP_CWD=", t);
425+
426diff --git a/debian/patches/CVE-2022-45873.patch b/debian/patches/CVE-2022-45873.patch
427new file mode 100644
428index 0000000..2badbcb
429--- /dev/null
430+++ b/debian/patches/CVE-2022-45873.patch
431@@ -0,0 +1,115 @@
432+From 076b807be472630692c5348c60d0c2b7b28ad437 Mon Sep 17 00:00:00 2001
433+From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
434+Date: Tue, 18 Oct 2022 18:23:53 +0200
435+Subject: [PATCH] coredump: avoid deadlock when passing processed backtrace
436+ data
437+
438+We would deadlock when passing the data back from the forked-off process that
439+was doing backtrace generation back to the coredump parent. This is because we
440+fork the child and wait for it to exit. The child tries to write too much data
441+to the output pipe, and and after the first 64k blocks on the parent because
442+the pipe is full. The bug surfaced in Fedora because of a combination of four
443+factors:
444+- 87707784c70dc9894ec613df0a6e75e732a362a3 was backported to v251.5, which
445+ allowed coredump processing to be successful.
446+- 1a0281a3ebf4f8c16d40aa9e63103f16cd23bb2a was NOT backported, so the output
447+ was very verbose.
448+- Fedora has the ELF package metadata available, so a lot of output can be
449+ generated. Most other distros just don't have the information.
450+- gnome-calendar crashes and has a bazillion modules and 69596 bytes of output
451+ are generated for it.
452+
453+Fixes https://bugzilla.redhat.com/show_bug.cgi?id=2135778.
454+
455+The code is changed to try to write data opportunistically. If we get partial
456+information, that is still logged. In is generally better to log partial
457+backtrace information than nothing at all.
458+---
459+ src/shared/elf-util.c | 37 +++++++++++++++++++++++++++++++------
460+ 1 file changed, 31 insertions(+), 6 deletions(-)
461+
462+--- systemd-251.4.orig/src/shared/elf-util.c
463++++ systemd-251.4/src/shared/elf-util.c
464+@@ -30,6 +30,9 @@
465+ #define THREADS_MAX 64
466+ #define ELF_PACKAGE_METADATA_ID 0xcafe1a7e
467+
468++/* The amount of data we're willing to write to each of the output pipes. */
469++#define COREDUMP_PIPE_MAX (1024*1024U)
470++
471+ static void *dw_dl = NULL;
472+ static void *elf_dl = NULL;
473+
474+@@ -704,13 +707,13 @@ int parse_elf_object(int fd, const char
475+ return r;
476+
477+ if (ret) {
478+- r = RET_NERRNO(pipe2(return_pipe, O_CLOEXEC));
479++ r = RET_NERRNO(pipe2(return_pipe, O_CLOEXEC|O_NONBLOCK));
480+ if (r < 0)
481+ return r;
482+ }
483+
484+ if (ret_package_metadata) {
485+- r = RET_NERRNO(pipe2(json_pipe, O_CLOEXEC));
486++ r = RET_NERRNO(pipe2(json_pipe, O_CLOEXEC|O_NONBLOCK));
487+ if (r < 0)
488+ return r;
489+ }
490+@@ -754,8 +757,24 @@ int parse_elf_object(int fd, const char
491+ goto child_fail;
492+
493+ if (buf) {
494+- r = loop_write(return_pipe[1], buf, strlen(buf), false);
495+- if (r < 0)
496++ size_t len = strlen(buf);
497++
498++ if (len > COREDUMP_PIPE_MAX) {
499++ /* This is iffy. A backtrace can be a few hundred kilobytes, but too much is
500++ * too much. Let's log a warning and ignore the rest. */
501++ log_warning("Generated backtrace is %zu bytes (more than the limit of %u bytes), backtrace will be truncated.",
502++ len, COREDUMP_PIPE_MAX);
503++ len = COREDUMP_PIPE_MAX;
504++ }
505++
506++ /* Bump the space for the returned string.
507++ * Failure is ignored, because partial output is still useful. */
508++ (void) fcntl(return_pipe[1], F_SETPIPE_SZ, len);
509++
510++ r = loop_write(return_pipe[1], buf, len, false);
511++ if (r == -EAGAIN)
512++ log_warning("Write failed, backtrace will be truncated.");
513++ else if (r < 0)
514+ goto child_fail;
515+
516+ return_pipe[1] = safe_close(return_pipe[1]);
517+@@ -764,13 +783,19 @@ int parse_elf_object(int fd, const char
518+ if (package_metadata) {
519+ _cleanup_fclose_ FILE *json_out = NULL;
520+
521++ /* Bump the space for the returned string. We don't know how much space we'll need in
522++ * advance, so we'll just try to write as much as possible and maybe fail later. */
523++ (void) fcntl(json_pipe[1], F_SETPIPE_SZ, COREDUMP_PIPE_MAX);
524++
525+ json_out = take_fdopen(&json_pipe[1], "w");
526+ if (!json_out) {
527+ r = -errno;
528+ goto child_fail;
529+ }
530+
531+- json_variant_dump(package_metadata, JSON_FORMAT_FLUSH, json_out, NULL);
532++ r = json_variant_dump(package_metadata, JSON_FORMAT_FLUSH, json_out, NULL);
533++ if (r < 0)
534++ log_warning_errno(r, "Failed to write JSON package metadata, ignoring: %m");
535+ }
536+
537+ _exit(EXIT_SUCCESS);
538+@@ -805,7 +830,7 @@ int parse_elf_object(int fd, const char
539+
540+ r = json_parse_file(json_in, NULL, 0, &package_metadata, NULL, NULL);
541+ if (r < 0 && r != -EINVAL) /* EINVAL: json was empty, so we got nothing, but that's ok */
542+- return r;
543++ log_warning_errno(r, "Failed to read or parse json metadata, ignoring: %m");
544+ }
545+
546+ if (ret)
547diff --git a/debian/patches/backport-for-CVE-2022-45873.patch b/debian/patches/backport-for-CVE-2022-45873.patch
548new file mode 100644
549index 0000000..857fd1d
550--- /dev/null
551+++ b/debian/patches/backport-for-CVE-2022-45873.patch
552@@ -0,0 +1,45 @@
553+From 7922ead507e0d83e4ec72a8cbd2b67194766e58c Mon Sep 17 00:00:00 2001
554+From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
555+Date: Tue, 18 Oct 2022 18:09:06 +0200
556+Subject: [PATCH] shared/json: allow json_variant_dump() to return an error
557+
558+---
559+ src/shared/json.c | 7 ++++---
560+ src/shared/json.h | 2 +-
561+ 2 files changed, 5 insertions(+), 4 deletions(-)
562+
563+--- systemd-251.4.orig/src/shared/json.c
564++++ systemd-251.4/src/shared/json.c
565+@@ -1770,9 +1770,9 @@ int json_variant_format(JsonVariant *v,
566+ return (int) sz - 1;
567+ }
568+
569+-void json_variant_dump(JsonVariant *v, JsonFormatFlags flags, FILE *f, const char *prefix) {
570++int json_variant_dump(JsonVariant *v, JsonFormatFlags flags, FILE *f, const char *prefix) {
571+ if (!v)
572+- return;
573++ return 0;
574+
575+ if (!f)
576+ f = stdout;
577+@@ -1798,7 +1798,8 @@ void json_variant_dump(JsonVariant *v, J
578+ fputc('\n', f); /* In case of SSE add a second newline */
579+
580+ if (flags & JSON_FORMAT_FLUSH)
581+- fflush(f);
582++ return fflush_and_check(f);
583++ return 0;
584+ }
585+
586+ int json_variant_filter(JsonVariant **v, char **to_remove) {
587+--- systemd-251.4.orig/src/shared/json.h
588++++ systemd-251.4/src/shared/json.h
589+@@ -195,7 +195,7 @@ typedef enum JsonFormatFlags {
590+ } JsonFormatFlags;
591+
592+ int json_variant_format(JsonVariant *v, JsonFormatFlags flags, char **ret);
593+-void json_variant_dump(JsonVariant *v, JsonFormatFlags flags, FILE *f, const char *prefix);
594++int json_variant_dump(JsonVariant *v, JsonFormatFlags flags, FILE *f, const char *prefix);
595+
596+ int json_variant_filter(JsonVariant **v, char **to_remove);
597+
598diff --git a/debian/patches/lp2002445/sd-netlink-add-a-test-for-rtnl_set_link_name.patch b/debian/patches/lp2002445/sd-netlink-add-a-test-for-rtnl_set_link_name.patch
599new file mode 100644
600index 0000000..382f6ea
601--- /dev/null
602+++ b/debian/patches/lp2002445/sd-netlink-add-a-test-for-rtnl_set_link_name.patch
603@@ -0,0 +1,66 @@
604+From: Nick Rosbrook <nick.rosbrook@canonical.com>
605+Date: Tue, 22 Nov 2022 17:01:47 -0500
606+Subject: sd-netlink: add a test for rtnl_set_link_name()
607+
608+Origin: upstream, https://github.com/systemd/systemd/commit/b338a8bb40
609+Bug-Ubuntu: https://launchpad.net/bugs/2002445
610+
611+Add a test that verifies a deleted alternative name is restored on error
612+in rtnl_set_link_name().
613+---
614+ src/libsystemd/sd-netlink/test-netlink.c | 28 ++++++++++++++++++++++++++++
615+ 1 file changed, 28 insertions(+)
616+
617+diff --git a/src/libsystemd/sd-netlink/test-netlink.c b/src/libsystemd/sd-netlink/test-netlink.c
618+index fbc3ef0..440e9ce 100644
619+--- a/src/libsystemd/sd-netlink/test-netlink.c
620++++ b/src/libsystemd/sd-netlink/test-netlink.c
621+@@ -8,6 +8,7 @@
622+ #include <linux/if_macsec.h>
623+ #include <linux/l2tp.h>
624+ #include <linux/nl80211.h>
625++#include <unistd.h>
626+
627+ #include "sd-netlink.h"
628+
629+@@ -666,6 +667,32 @@ static void test_genl(void) {
630+ }
631+ }
632+
633++static void test_rtnl_set_link_name(sd_netlink *rtnl, int ifindex) {
634++ _cleanup_strv_free_ char **alternative_names = NULL;
635++ int r;
636++
637++ log_debug("/* %s */", __func__);
638++
639++ if (geteuid() != 0)
640++ return (void) log_tests_skipped("not root");
641++
642++ /* Test that the new name (which is currently an alternative name) is
643++ * restored as an alternative name on error. Create an error by using
644++ * an invalid device name, namely one that exceeds IFNAMSIZ
645++ * (alternative names can exceed IFNAMSIZ, but not regular names). */
646++ r = rtnl_set_link_alternative_names(&rtnl, ifindex, STRV_MAKE("testlongalternativename"));
647++ if (r == -EPERM)
648++ return (void) log_tests_skipped("missing required capabilities");
649++ if (r == -EOPNOTSUPP)
650++ return (void) log_tests_skipped("alternative name is not supported");
651++
652++ assert_se(r >= 0);
653++ assert_se(rtnl_set_link_name(&rtnl, ifindex, "testlongalternativename") == -EINVAL);
654++ assert_se(rtnl_get_link_alternative_names(&rtnl, ifindex, &alternative_names) >= 0);
655++ assert_se(strv_contains(alternative_names, "testlongalternativename"));
656++ assert_se(rtnl_delete_link_alternative_names(&rtnl, ifindex, STRV_MAKE("testlongalternativename")) >= 0);
657++}
658++
659+ int main(void) {
660+ sd_netlink *rtnl;
661+ sd_netlink_message *m;
662+@@ -697,6 +724,7 @@ int main(void) {
663+ test_pipe(if_loopback);
664+ test_event_loop(if_loopback);
665+ test_link_configure(rtnl, if_loopback);
666++ test_rtnl_set_link_name(rtnl, if_loopback);
667+
668+ test_get_addresses(rtnl);
669+ test_message_link_bridge(rtnl);
670diff --git a/debian/patches/lp2002445/sd-netlink-do-not-swap-old-name-and-alternative-name.patch b/debian/patches/lp2002445/sd-netlink-do-not-swap-old-name-and-alternative-name.patch
671new file mode 100644
672index 0000000..2cf4997
673--- /dev/null
674+++ b/debian/patches/lp2002445/sd-netlink-do-not-swap-old-name-and-alternative-name.patch
675@@ -0,0 +1,54 @@
676+From: Nick Rosbrook <nick.rosbrook@canonical.com>
677+Date: Fri, 2 Dec 2022 15:26:18 -0500
678+Subject: sd-netlink: do not swap old name and alternative name
679+
680+Origin: upstream, https://github.com/systemd/systemd/commit/080afbb57c
681+Bug-Ubuntu: https://launchpad.net/bugs/2002445
682+
683+Commit 434a348380 ("netlink: do not fail when new interface name is
684+already used as an alternative name") added logic to set the old
685+interface name as an alternative name, but only when the new name is
686+currently an alternative name. This is not the desired outcome in most
687+cases, and the important part of this commit was to delete the new name
688+from the list of alternative names if necessary.
689+---
690+ src/libsystemd/sd-netlink/netlink-util.c | 12 ------------
691+ 1 file changed, 12 deletions(-)
692+
693+diff --git a/src/libsystemd/sd-netlink/netlink-util.c b/src/libsystemd/sd-netlink/netlink-util.c
694+index ce2c4f3..f88169e 100644
695+--- a/src/libsystemd/sd-netlink/netlink-util.c
696++++ b/src/libsystemd/sd-netlink/netlink-util.c
697+@@ -12,7 +12,6 @@
698+ int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name) {
699+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL;
700+ _cleanup_strv_free_ char **alternative_names = NULL;
701+- char old_name[IF_NAMESIZE] = {};
702+ int r;
703+
704+ assert(rtnl);
705+@@ -32,10 +31,6 @@ int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name) {
706+ if (r < 0)
707+ return log_debug_errno(r, "Failed to remove '%s' from alternative names on network interface %i: %m",
708+ name, ifindex);
709+-
710+- r = format_ifname(ifindex, old_name);
711+- if (r < 0)
712+- return log_debug_errno(r, "Failed to get current name of network interface %i: %m", ifindex);
713+ }
714+
715+ r = sd_rtnl_message_new_link(*rtnl, &message, RTM_SETLINK, ifindex);
716+@@ -50,13 +45,6 @@ int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name) {
717+ if (r < 0)
718+ return r;
719+
720+- if (!isempty(old_name)) {
721+- r = rtnl_set_link_alternative_names(rtnl, ifindex, STRV_MAKE(old_name));
722+- if (r < 0)
723+- log_debug_errno(r, "Failed to set '%s' as an alternative name on network interface %i, ignoring: %m",
724+- old_name, ifindex);
725+- }
726+-
727+ return 0;
728+ }
729+
730diff --git a/debian/patches/lp2002445/sd-netlink-restore-altname-on-error-in-rtnl_set_link_name.patch b/debian/patches/lp2002445/sd-netlink-restore-altname-on-error-in-rtnl_set_link_name.patch
731new file mode 100644
732index 0000000..a5e2e24
733--- /dev/null
734+++ b/debian/patches/lp2002445/sd-netlink-restore-altname-on-error-in-rtnl_set_link_name.patch
735@@ -0,0 +1,64 @@
736+From: Nick Rosbrook <nick.rosbrook@canonical.com>
737+Date: Wed, 2 Nov 2022 05:36:14 -0400
738+Subject: sd-netlink: restore altname on error in rtnl_set_link_name
739+
740+Origin: upstream, https://github.com/systemd/systemd/commit/4d600667f8
741+Bug-Ubuntu: https://launchpad.net/bugs/2002445
742+
743+If a current alternative name is to be used to rename a network
744+interface, the alternative name must be removed first. If interface
745+renaming fails, restore the alternative name that was deleted if
746+necessary.
747+---
748+ src/libsystemd/sd-netlink/netlink-util.c | 19 ++++++++++++++++---
749+ 1 file changed, 16 insertions(+), 3 deletions(-)
750+
751+diff --git a/src/libsystemd/sd-netlink/netlink-util.c b/src/libsystemd/sd-netlink/netlink-util.c
752+index 7f2596d..c4ead31 100644
753+--- a/src/libsystemd/sd-netlink/netlink-util.c
754++++ b/src/libsystemd/sd-netlink/netlink-util.c
755+@@ -11,6 +11,7 @@
756+ int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name) {
757+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL;
758+ _cleanup_strv_free_ char **alternative_names = NULL;
759++ bool altname_deleted = false;
760+ int r;
761+
762+ assert(rtnl);
763+@@ -30,21 +31,33 @@ int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name) {
764+ if (r < 0)
765+ return log_debug_errno(r, "Failed to remove '%s' from alternative names on network interface %i: %m",
766+ name, ifindex);
767++
768++ altname_deleted = true;
769+ }
770+
771+ r = sd_rtnl_message_new_link(*rtnl, &message, RTM_SETLINK, ifindex);
772+ if (r < 0)
773+- return r;
774++ goto fail;
775+
776+ r = sd_netlink_message_append_string(message, IFLA_IFNAME, name);
777+ if (r < 0)
778+- return r;
779++ goto fail;
780+
781+ r = sd_netlink_call(*rtnl, message, 0, NULL);
782+ if (r < 0)
783+- return r;
784++ goto fail;
785+
786+ return 0;
787++
788++fail:
789++ if (altname_deleted) {
790++ int q = rtnl_set_link_alternative_names(rtnl, ifindex, STRV_MAKE(name));
791++ if (q < 0)
792++ log_debug_errno(q, "Failed to restore '%s' as an alternative name on network interface %i, ignoring: %m",
793++ name, ifindex);
794++ }
795++
796++ return r;
797+ }
798+
799+ int rtnl_set_link_properties(
800diff --git a/debian/patches/lp2002445/udev-attempt-device-rename-even-if-interface-is-up.patch b/debian/patches/lp2002445/udev-attempt-device-rename-even-if-interface-is-up.patch
801new file mode 100644
802index 0000000..5ffc818
803--- /dev/null
804+++ b/debian/patches/lp2002445/udev-attempt-device-rename-even-if-interface-is-up.patch
805@@ -0,0 +1,61 @@
806+From: Nick Rosbrook <nick.rosbrook@canonical.com>
807+Date: Fri, 2 Dec 2022 15:35:25 -0500
808+Subject: udev: attempt device rename even if interface is up
809+
810+Origin: upstream, https://github.com/systemd/systemd/commit/53584e7b61
811+Bug-Ubuntu: https://launchpad.net/bugs/2002445
812+
813+Currently rename_netif() will not attempt to rename a device if it is
814+already up, because the kernel will return -EBUSY unless live renaming
815+is allowed on the device. This restriction will be removed in a future
816+kernel version [1].
817+
818+To cover both cases, always attempt to rename the interface and return 0
819+if we get -EBUSY.
820+
821+[1] https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git/commit/?id=bd039b5ea2a9
822+---
823+ src/udev/udev-event.c | 16 +++++-----------
824+ 1 file changed, 5 insertions(+), 11 deletions(-)
825+
826+diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c
827+index 9b53105..681aa87 100644
828+--- a/src/udev/udev-event.c
829++++ b/src/udev/udev-event.c
830+@@ -871,7 +871,6 @@ int udev_event_spawn(
831+ static int rename_netif(UdevEvent *event) {
832+ const char *oldname;
833+ sd_device *dev;
834+- unsigned flags;
835+ int ifindex, r;
836+
837+ assert(event);
838+@@ -905,16 +904,6 @@ static int rename_netif(UdevEvent *event) {
839+ return 0;
840+ }
841+
842+- r = rtnl_get_link_info(&event->rtnl, ifindex, NULL, &flags, NULL, NULL, NULL);
843+- if (r < 0)
844+- return log_device_warning_errno(dev, r, "Failed to get link flags: %m");
845+-
846+- if (FLAGS_SET(flags, IFF_UP)) {
847+- log_device_info(dev, "Network interface '%s' is already up, refusing to rename to '%s'.",
848+- oldname, event->name);
849+- return 0;
850+- }
851+-
852+ /* Set ID_RENAMING boolean property here, and drop it in the corresponding move uevent later. */
853+ r = device_add_property(dev, "ID_RENAMING", "1");
854+ if (r < 0)
855+@@ -936,6 +925,11 @@ static int rename_netif(UdevEvent *event) {
856+ return log_device_debug_errno(event->dev_db_clone, r, "Failed to update database under /run/udev/data/: %m");
857+
858+ r = rtnl_set_link_name(&event->rtnl, ifindex, event->name);
859++ if (r == -EBUSY) {
860++ log_device_info(dev, "Network interface '%s' is already up, cannot rename to '%s'.",
861++ oldname, event->name);
862++ return 0;
863++ }
864+ if (r < 0)
865+ return log_device_error_errno(dev, r, "Failed to rename network interface %i from '%s' to '%s': %m",
866+ ifindex, oldname, event->name);
867diff --git a/debian/patches/lp2002445/udev-net-allow-new-link-name-as-an-altname-before-renamin.patch b/debian/patches/lp2002445/udev-net-allow-new-link-name-as-an-altname-before-renamin.patch
868new file mode 100644
869index 0000000..0d651a2
870--- /dev/null
871+++ b/debian/patches/lp2002445/udev-net-allow-new-link-name-as-an-altname-before-renamin.patch
872@@ -0,0 +1,34 @@
873+From: Nick Rosbrook <nick.rosbrook@canonical.com>
874+Date: Wed, 2 Nov 2022 11:05:01 -0400
875+Subject: udev/net: allow new link name as an altname before renaming happens
876+
877+Origin: upstream, https://github.com/systemd/systemd/commit/d0b31efc1a
878+Bug-Ubuntu: https://launchpad.net/bugs/2002445
879+
880+When configuring a link's alternative names, the link's new name to-be
881+is not allowed to be included because interface renaming will fail if
882+the new name is already present as an alternative name. However,
883+rtnl_set_link_name will delete the conflicting alternative name before
884+renaming the device, if necessary.
885+
886+Allow the new link name to be set as an alternative name before the
887+device is renamed. This means that if the rename is later skipped (i.e.
888+because the link is already up), then the name can at least still be
889+present as an alternative name.
890+---
891+ src/udev/net/link-config.c | 2 --
892+ 1 file changed, 2 deletions(-)
893+
894+diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c
895+index 28c0e63..cdad078 100644
896+--- a/src/udev/net/link-config.c
897++++ b/src/udev/net/link-config.c
898+@@ -844,8 +844,6 @@ static int link_apply_alternative_names(Link *link, sd_netlink **rtnl) {
899+ }
900+ }
901+
902+- if (link->new_name)
903+- strv_remove(altnames, link->new_name);
904+ strv_remove(altnames, link->ifname);
905+
906+ r = rtnl_get_link_alternative_names(rtnl, link->ifindex, &current_altnames);
907diff --git a/debian/patches/lp2004478-network-dhcp4-accept-local-subnet-routes-from-DHCP.patch b/debian/patches/lp2004478-network-dhcp4-accept-local-subnet-routes-from-DHCP.patch
908new file mode 100644
909index 0000000..6bc3b3c
910--- /dev/null
911+++ b/debian/patches/lp2004478-network-dhcp4-accept-local-subnet-routes-from-DHCP.patch
912@@ -0,0 +1,54 @@
913+From: Tuetuopay <tuetuopay@me.com>
914+Date: Fri, 27 Jan 2023 15:10:49 +0100
915+Subject: network/dhcp4: accept local subnet routes from DHCP
916+
917+Origin: upstream, https://github.com/systemd/systemd/commit/1d84a3c7792a8910b05904937c703307ca19740f
918+Bug-Ubuntu: https://launchpad.net/bugs/2004478
919+
920+RFC3442 specifies option 121 (Classless Static Routes) that allow a DHCP
921+server to push arbitrary routes to a client. It has a Local Subnet
922+Routes section expliciting the behavior of routes with a null (0.0.0.0)
923+gateway.
924+
925+Such routes are to be installed on the interface with a Link scope, to
926+mark them as directly available on the link without any gateway.
927+
928+Networkd currently drops those routes, which is against the RFC, as
929+Linux has proper support for such routes.
930+
931+Fixes: 7f20627 ("network: dhcp4: ignore gateway in static routes if destination is link-local or in the same network")
932+---
933+ src/network/networkd-dhcp4.c | 19 +++++++++++--------
934+ 1 file changed, 11 insertions(+), 8 deletions(-)
935+
936+diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c
937+index 0941ad0..7b1133e 100644
938+--- a/src/network/networkd-dhcp4.c
939++++ b/src/network/networkd-dhcp4.c
940+@@ -376,15 +376,18 @@ static int dhcp4_request_route_auto(
941+ route->gw = IN_ADDR_NULL;
942+ route->prefsrc.in = address;
943+
944+- } else {
945+- if (in4_addr_is_null(gw)) {
946+- log_link_debug(link, "DHCP: requested route destination "IPV4_ADDRESS_FMT_STR"/%u is not in the assigned network "
947+- IPV4_ADDRESS_FMT_STR"/%u, but no gateway is specified, ignoring.",
948+- IPV4_ADDRESS_FMT_VAL(route->dst.in), route->dst_prefixlen,
949+- IPV4_ADDRESS_FMT_VAL(prefix), prefixlen);
950+- return 0;
951+- }
952++ } else if (in4_addr_is_null(gw)) {
953++ log_link_debug(link, "DHCP: requested route destination "IPV4_ADDRESS_FMT_STR"/%u is not in the assigned network "
954++ IPV4_ADDRESS_FMT_STR"/%u, but no gateway is specified, using 'link' scope.",
955++ IPV4_ADDRESS_FMT_VAL(route->dst.in), route->dst_prefixlen,
956++ IPV4_ADDRESS_FMT_VAL(prefix), prefixlen);
957+
958++ route->scope = RT_SCOPE_LINK;
959++ route->gw_family = AF_UNSPEC;
960++ route->gw = IN_ADDR_NULL;
961++ route->prefsrc.in = address;
962++
963++ } else {
964+ r = dhcp4_request_route_to_gateway(link, gw);
965+ if (r < 0)
966+ return r;
967diff --git a/debian/patches/series b/debian/patches/series
968index 5b33e52..24359ad 100644
969--- a/debian/patches/series
970+++ b/debian/patches/series
971@@ -52,3 +52,12 @@ lp1981042-core-firstboot-workaround-timezone-issues-caused-by-Ubunt.patch
972 test-denylist-TEST-29-PORTABLE-again.patch
973 lp1989969-test-deny-list-TEST-36-NUMAPOLICY-on-ppc64el.patch
974 lp1991829-add-CAP_LINUX_IMMUTABLE-to-systemd-machined-so-it-ca.patch
975+CVE-2022-4415.patch
976+backport-for-CVE-2022-45873.patch
977+CVE-2022-45873.patch
978+lp2004478-network-dhcp4-accept-local-subnet-routes-from-DHCP.patch
979+lp2002445/udev-net-allow-new-link-name-as-an-altname-before-renamin.patch
980+lp2002445/sd-netlink-do-not-swap-old-name-and-alternative-name.patch
981+lp2002445/sd-netlink-restore-altname-on-error-in-rtnl_set_link_name.patch
982+lp2002445/udev-attempt-device-rename-even-if-interface-is-up.patch
983+lp2002445/sd-netlink-add-a-test-for-rtnl_set_link_name.patch

Subscribers

People subscribed via source and target branches