xref: /OK3568_Linux_fs/yocto/poky/meta/recipes-core/systemd/systemd/CVE-2022-45873.patch (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1From 076b807be472630692c5348c60d0c2b7b28ad437 Mon Sep 17 00:00:00 2001
2From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
3Date: Tue, 18 Oct 2022 18:23:53 +0200
4Subject: [PATCH] coredump: avoid deadlock when passing processed backtrace
5 data
6
7We would deadlock when passing the data back from the forked-off process that
8was doing backtrace generation back to the coredump parent. This is because we
9fork the child and wait for it to exit. The child tries to write too much data
10to the output pipe, and and after the first 64k blocks on the parent because
11the pipe is full. The bug surfaced in Fedora because of a combination of four
12factors:
13- 87707784c70dc9894ec613df0a6e75e732a362a3 was backported to v251.5, which
14  allowed coredump processing to be successful.
15- 1a0281a3ebf4f8c16d40aa9e63103f16cd23bb2a was NOT backported, so the output
16  was very verbose.
17- Fedora has the ELF package metadata available, so a lot of output can be
18  generated. Most other distros just don't have the information.
19- gnome-calendar crashes and has a bazillion modules and 69596 bytes of output
20  are generated for it.
21
22Fixes https://bugzilla.redhat.com/show_bug.cgi?id=2135778.
23
24The code is changed to try to write data opportunistically. If we get partial
25information, that is still logged. In is generally better to log partial
26backtrace information than nothing at all.
27
28Upstream-Status: Backport [https://github.com/systemd/systemd/commit/076b807be472630692c5348c60d0c2b7b28ad437]
29CVE: CVE-2022-45873
30Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com>
31---
32 src/shared/elf-util.c | 37 +++++++++++++++++++++++++++++++------
33 1 file changed, 31 insertions(+), 6 deletions(-)
34
35diff --git a/src/shared/elf-util.c b/src/shared/elf-util.c
36index 6d9fcfbbf2..bd27507346 100644
37--- a/src/shared/elf-util.c
38+++ b/src/shared/elf-util.c
39@@ -30,6 +30,9 @@
40 #define THREADS_MAX 64
41 #define ELF_PACKAGE_METADATA_ID 0xcafe1a7e
42
43+/* The amount of data we're willing to write to each of the output pipes. */
44+#define COREDUMP_PIPE_MAX (1024*1024U)
45+
46 static void *dw_dl = NULL;
47 static void *elf_dl = NULL;
48
49@@ -700,13 +703,13 @@ int parse_elf_object(int fd, const char *executable, bool fork_disable_dump, cha
50                 return r;
51
52         if (ret) {
53-                r = RET_NERRNO(pipe2(return_pipe, O_CLOEXEC));
54+                r = RET_NERRNO(pipe2(return_pipe, O_CLOEXEC|O_NONBLOCK));
55                 if (r < 0)
56                         return r;
57         }
58
59         if (ret_package_metadata) {
60-                r = RET_NERRNO(pipe2(json_pipe, O_CLOEXEC));
61+                r = RET_NERRNO(pipe2(json_pipe, O_CLOEXEC|O_NONBLOCK));
62                 if (r < 0)
63                         return r;
64         }
65@@ -750,8 +753,24 @@ int parse_elf_object(int fd, const char *executable, bool fork_disable_dump, cha
66                         goto child_fail;
67
68                 if (buf) {
69-                        r = loop_write(return_pipe[1], buf, strlen(buf), false);
70-                        if (r < 0)
71+                        size_t len = strlen(buf);
72+
73+                        if (len > COREDUMP_PIPE_MAX) {
74+                                /* This is iffy. A backtrace can be a few hundred kilobytes, but too much is
75+                                 * too much. Let's log a warning and ignore the rest. */
76+                                log_warning("Generated backtrace is %zu bytes (more than the limit of %u bytes), backtrace will be truncated.",
77+                                            len, COREDUMP_PIPE_MAX);
78+                                len = COREDUMP_PIPE_MAX;
79+                        }
80+
81+                        /* Bump the space for the returned string.
82+                         * Failure is ignored, because partial output is still useful. */
83+                        (void) fcntl(return_pipe[1], F_SETPIPE_SZ, len);
84+
85+                        r = loop_write(return_pipe[1], buf, len, false);
86+                        if (r == -EAGAIN)
87+                                log_warning("Write failed, backtrace will be truncated.");
88+                        else if (r < 0)
89                                 goto child_fail;
90
91                         return_pipe[1] = safe_close(return_pipe[1]);
92@@ -760,13 +779,19 @@ int parse_elf_object(int fd, const char *executable, bool fork_disable_dump, cha
93                 if (package_metadata) {
94                         _cleanup_fclose_ FILE *json_out = NULL;
95
96+                        /* Bump the space for the returned string. We don't know how much space we'll need in
97+                         * advance, so we'll just try to write as much as possible and maybe fail later. */
98+                        (void) fcntl(json_pipe[1], F_SETPIPE_SZ, COREDUMP_PIPE_MAX);
99+
100                         json_out = take_fdopen(&json_pipe[1], "w");
101                         if (!json_out) {
102                                 r = -errno;
103                                 goto child_fail;
104                         }
105
106-                        json_variant_dump(package_metadata, JSON_FORMAT_FLUSH, json_out, NULL);
107+                        r = json_variant_dump(package_metadata, JSON_FORMAT_FLUSH, json_out, NULL);
108+                        if (r < 0)
109+                                log_warning_errno(r, "Failed to write JSON package metadata, ignoring: %m");
110                 }
111
112                 _exit(EXIT_SUCCESS);
113@@ -801,7 +826,7 @@ int parse_elf_object(int fd, const char *executable, bool fork_disable_dump, cha
114
115                 r = json_parse_file(json_in, NULL, 0, &package_metadata, NULL, NULL);
116                 if (r < 0 && r != -EINVAL) /* EINVAL: json was empty, so we got nothing, but that's ok */
117-                        return r;
118+                        log_warning_errno(r, "Failed to read or parse json metadata, ignoring: %m");
119         }
120
121         if (ret)
122--
1232.25.1
124
125