Merge ~slyon/ubuntu/+source/systemd:slyon/resolved-segfault-root-cause into ~ubuntu-core-dev/ubuntu/+source/systemd:ubuntu-hirsute

Proposed by Lukas Märdian
Status: Needs review
Proposed branch: ~slyon/ubuntu/+source/systemd:slyon/resolved-segfault-root-cause
Merge into: ~ubuntu-core-dev/ubuntu/+source/systemd:ubuntu-hirsute
Diff against target: 331 lines (+239/-17)
4 files modified
debian/changelog (+11/-0)
debian/patches/resolved-disable-event-sources-before-unreffing-them.patch (+22/-16)
debian/patches/resolved-fix-braino-with-reference-counting-and-linked-li.patch (+204/-0)
debian/patches/series (+2/-1)
Reviewer Review Type Date Requested Status
Dan Streetman Pending
Review via email: mp+408886@code.launchpad.net

Description of the change

resolved: cherry-pick upstream commits to fix segfault (LP: #1934221)

Replace d/p/lp1934221-resolved-disable-event-sources-before-unreffing-them.patch with upstream commit from systemd v247-stable branch (d/p/resolved-disable-event-sources-before-unreffing-them.patch) and add d/p/resolved-fix-braino-with-reference-counting-and-linked-li.patch

The additional patch is a fixup of an already included (in systemd-stable v247.3) patch "resolved: use reference counting for DnsQueryCandidate objects" and should help with avoiding the query related segfaults.
There haven't been any other relevant commits to resolved-dns-query.c in v247-stable nor upstream/master.

I have not been able to reproduce this problem locally as it happens only sporadically. Applying this fixup and observing if this crash does still happen in Hirsute should be a good measure of success, before backporting the changes to Focal:
https://errors.ubuntu.com/problem/c4e5be3f1c7af9483993c7e6007b9325ab5b78cd

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

I'm also working with the original bug reporter, trying to get confirmation about this issue being fixed in a PPA: https://launchpad.net/~slyon/+archive/ubuntu/lp1934221/+packages

https://bugs.launchpad.net/ubuntu/+source/systemd/+bug/1934221

Unmerged commits

70bbdb1... by Lukas Märdian

update changelog

38b83d3... by Lukas Märdian

resolved: cherry-pick upstream commits to fix segfault (LP: #1934221)

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 b003153..ad663b6 100644
3--- a/debian/changelog
4+++ b/debian/changelog
5@@ -1,3 +1,14 @@
6+systemd (247.3-3ubuntu3.7) UNRELEASED; urgency=medium
7+
8+ * resolved: cherry-pick upstream commits to fix segfault (LP: #1934221)
9+ Files:
10+ - debian/patches/lp1934221-resolved-disable-event-sources-before-unreffing-them.patch
11+ - debian/patches/resolved-disable-event-sources-before-unreffing-them.patch
12+ - debian/patches/resolved-fix-braino-with-reference-counting-and-linked-li.patch
13+ https://git.launchpad.net/~ubuntu-core-dev/ubuntu/+source/systemd/commit/?id=38b83d38337046fca83fbf3fef1c02309295ab14
14+
15+ -- Lukas Märdian <slyon@ubuntu.com> Mon, 20 Sep 2021 13:13:11 +0200
16+
17 systemd (247.3-3ubuntu3.6) hirsute; urgency=medium
18
19 * d/p/dell-clamshell-accel-location-base-with-sku.patch:
20diff --git a/debian/patches/lp1934221-resolved-disable-event-sources-before-unreffing-them.patch b/debian/patches/resolved-disable-event-sources-before-unreffing-them.patch
21similarity index 85%
22rename from debian/patches/lp1934221-resolved-disable-event-sources-before-unreffing-them.patch
23rename to debian/patches/resolved-disable-event-sources-before-unreffing-them.patch
24index c916d9a..f77ff1c 100644
25--- a/debian/patches/lp1934221-resolved-disable-event-sources-before-unreffing-them.patch
26+++ b/debian/patches/resolved-disable-event-sources-before-unreffing-them.patch
27@@ -1,8 +1,6 @@
28-From: Lukas Märdian <slyon@ubuntu.com>
29-Date: Tue, 20 Jul 2021 14:43:31 +0200
30+From: =?utf-8?q?Zbigniew_J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
31+Date: Mon, 1 Mar 2021 23:10:06 +0100
32 Subject: resolved: disable event sources before unreffing them
33-Origin: upstream, https://github.com/systemd/systemd/commit/97935302283729c9206b84f5e00b1aff0f78ad19
34-Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/systemd/+bug/1934221
35
36 We generally operate on the assumption that a source is "gone" as soon
37 as we unref it. This is generally true because we have the only reference.
38@@ -19,15 +17,17 @@ are non-floating, so there is no reference from the sd_event object to the
39 sources.
40
41 For #18427.
42+
43+(cherry picked from commit 97935302283729c9206b84f5e00b1aff0f78ad19)
44 ---
45- src/resolve/resolved-dns-query.c | 2 +-
46- src/resolve/resolved-dns-scope.c | 8 ++++----
47- src/resolve/resolved-dns-stream.c | 4 ++--
48- src/resolve/resolved-dns-stub.c | 8 ++++----
49- src/resolve/resolved-dns-transaction.c | 4 ++--
50- src/resolve/resolved-llmnr.c | 8 ++++----
51- src/resolve/resolved-mdns.c | 4 ++--
52- 7 files changed, 19 insertions(+), 19 deletions(-)
53+ src/resolve/resolved-dns-query.c | 2 +-
54+ src/resolve/resolved-dns-scope.c | 8 ++++----
55+ src/resolve/resolved-dns-stream.c | 4 ++--
56+ src/resolve/resolved-dns-stub.c | 10 +++++-----
57+ src/resolve/resolved-dns-transaction.c | 5 +++--
58+ src/resolve/resolved-llmnr.c | 8 ++++----
59+ src/resolve/resolved-mdns.c | 4 ++--
60+ 7 files changed, 21 insertions(+), 20 deletions(-)
61
62 diff --git a/src/resolve/resolved-dns-query.c b/src/resolve/resolved-dns-query.c
63 index 8ee4fd8..f6ff3b5 100644
64@@ -92,7 +92,7 @@ index 1aab089..1471628 100644
65
66 /* Disconnect us from the server object if we are now not usable anymore */
67 diff --git a/src/resolve/resolved-dns-stub.c b/src/resolve/resolved-dns-stub.c
68-index 6a3dc99..63a57cb 100644
69+index 6a3dc99..5043c60 100644
70 --- a/src/resolve/resolved-dns-stub.c
71 +++ b/src/resolve/resolved-dns-stub.c
72 @@ -79,8 +79,8 @@ DnsStubListenerExtra *dns_stub_listener_extra_free(DnsStubListenerExtra *p) {
73@@ -106,7 +106,7 @@ index 6a3dc99..63a57cb 100644
74
75 return mfree(p);
76 }
77-@@ -763,8 +763,8 @@ int manager_dns_stub_start(Manager *m) {
78+@@ -763,12 +763,12 @@ int manager_dns_stub_start(Manager *m) {
79 void manager_dns_stub_stop(Manager *m) {
80 assert(m);
81
82@@ -117,16 +117,22 @@ index 6a3dc99..63a57cb 100644
83 }
84
85 static const char* const dns_stub_listener_mode_table[_DNS_STUB_LISTENER_MODE_MAX] = {
86+- [DNS_STUB_LISTENER_NO] = "no",
87++ [DNS_STUB_LISTENER_NO] = "no",
88+ [DNS_STUB_LISTENER_UDP] = "udp",
89+ [DNS_STUB_LISTENER_TCP] = "tcp",
90+ [DNS_STUB_LISTENER_YES] = "yes",
91 diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c
92-index 303233e..2b8e763 100644
93+index 303233e..a754283 100644
94 --- a/src/resolve/resolved-dns-transaction.c
95 +++ b/src/resolve/resolved-dns-transaction.c
96-@@ -59,14 +59,14 @@ static void dns_transaction_close_connection(DnsTransaction *t) {
97+@@ -59,14 +59,15 @@ static void dns_transaction_close_connection(DnsTransaction *t) {
98 t->stream = dns_stream_unref(t->stream);
99 }
100
101 - t->dns_udp_event_source = sd_event_source_unref(t->dns_udp_event_source);
102 + t->dns_udp_event_source = sd_event_source_disable_unref(t->dns_udp_event_source);
103++
104 t->dns_udp_fd = safe_close(t->dns_udp_fd);
105 }
106
107diff --git a/debian/patches/resolved-fix-braino-with-reference-counting-and-linked-li.patch b/debian/patches/resolved-fix-braino-with-reference-counting-and-linked-li.patch
108new file mode 100644
109index 0000000..75b9833
110--- /dev/null
111+++ b/debian/patches/resolved-fix-braino-with-reference-counting-and-linked-li.patch
112@@ -0,0 +1,204 @@
113+From: =?utf-8?q?Zbigniew_J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
114+Date: Fri, 14 May 2021 10:49:24 +0200
115+Subject: resolved: fix braino with reference counting and linked lists
116+
117+In 0e0fd08fc832b8f42e567d722d388eba086da5ff I added reference counts to keep
118+track of the DnsQueryCandidate objects. Unfortunately, dns_query_unref_candidates()
119+was written as
120+
121+ while (q->candidates)
122+ dns_query_candidate_unref(q->candidates);
123+
124+i.e. it would keep dropping the reference count as many times as needed for it
125+to hit 0, making the patch less than fully effective.
126+
127+dns_query_unref_candidates() is renamed to dns_query_detach_candidates() and
128+changed to drop exactly one reference from each of the linked candidates.
129+
130+Example failure:
131+==463== Invalid read of size 8
132+==463== at 0x419C93: dns_query_candidate_go (resolved-dns-query.c:159)
133+==463== by 0x41A143: dns_query_candidate_notify (resolved-dns-query.c:304)
134+==463== by 0x434BD6: dns_transaction_complete (resolved-dns-transaction.c:437)
135+==463== by 0x436A0F: dns_transaction_process_dnssec (resolved-dns-transaction.c:976)
136+==463== by 0x4378C1: dns_transaction_process_reply (resolved-dns-transaction.c:1387)
137+==463== by 0x437CE9: on_dns_packet (resolved-dns-transaction.c:1444)
138+==463== by 0x4B2DC9B: source_dispatch (sd-event.c:3512)
139+==463== by 0x4B2FB1F: sd_event_dispatch (sd-event.c:4077)
140+==463== by 0x4B2FFFA: sd_event_run (sd-event.c:4138)
141+==463== by 0x4B301D6: sd_event_loop (sd-event.c:4159)
142+==463== by 0x464A24: run (resolved.c:92)
143+==463== by 0x464B3C: main (resolved.c:99)
144+==463== Address 0x5f409d0 is 32 bytes inside a block of size 72 free'd
145+==463== at 0x48410E4: free (vg_replace_malloc.c:755)
146+==463== by 0x418EDF: mfree (alloc-util.h:48)
147+==463== by 0x4197E8: dns_query_candidate_free (resolved-dns-query.c:67)
148+==463== by 0x4198B7: dns_query_candidate_unref (resolved-dns-query.c:70)
149+==463== by 0x41A2E3: dns_query_unref_candidates (resolved-dns-query.c:337)
150+==463== by 0x41C5FE: dns_query_cname_redirect (resolved-dns-query.c:1028)
151+==463== by 0x41CA04: dns_query_process_cname_one (resolved-dns-query.c:1128)
152+==463== by 0x41CA80: dns_query_process_cname_many (resolved-dns-query.c:1157)
153+==463== by 0x40C0BD: bus_method_resolve_hostname_complete (resolved-bus.c:198)
154+==463== by 0x41B312: dns_query_complete (resolved-dns-query.c:562)
155+==463== by 0x41C1AC: dns_query_accept (resolved-dns-query.c:922)
156+==463== by 0x41C2C4: dns_query_ready (resolved-dns-query.c:955)
157+==463== by 0x41A162: dns_query_candidate_notify (resolved-dns-query.c:314)
158+==463== by 0x434BD6: dns_transaction_complete (resolved-dns-transaction.c:437)
159+==463== by 0x438995: dns_transaction_prepare (resolved-dns-transaction.c:1728)
160+==463== by 0x43921D: dns_transaction_go (resolved-dns-transaction.c:1928)
161+==463== by 0x419C7C: dns_query_candidate_go (resolved-dns-query.c:163)
162+==463== by 0x41A143: dns_query_candidate_notify (resolved-dns-query.c:304)
163+==463== by 0x434BD6: dns_transaction_complete (resolved-dns-transaction.c:437)
164+==463== by 0x436A0F: dns_transaction_process_dnssec (resolved-dns-transaction.c:976)
165+==463== by 0x4378C1: dns_transaction_process_reply (resolved-dns-transaction.c:1387)
166+==463== by 0x437CE9: on_dns_packet (resolved-dns-transaction.c:1444)
167+==463== by 0x4B2DC9B: source_dispatch (sd-event.c:3512)
168+==463== by 0x4B2FB1F: sd_event_dispatch (sd-event.c:4077)
169+==463== by 0x4B2FFFA: sd_event_run (sd-event.c:4138)
170+==463== by 0x4B301D6: sd_event_loop (sd-event.c:4159)
171+==463== by 0x464A24: run (resolved.c:92)
172+==463== by 0x464B3C: main (resolved.c:99)
173+==463== Block was alloc'd at
174+==463== at 0x483E86F: malloc (vg_replace_malloc.c:380)
175+==463== by 0x418F81: malloc_multiply (alloc-util.h:96)
176+==463== by 0x419378: dns_query_candidate_new (resolved-dns-query.c:23)
177+==463== by 0x41B42C: dns_query_add_candidate (resolved-dns-query.c:582)
178+==463== by 0x41BB7A: dns_query_go (resolved-dns-query.c:762)
179+==463== by 0x40CE3A: bus_method_resolve_hostname (resolved-bus.c:464)
180+==463== by 0x4A84B86: method_callbacks_run (bus-objects.c:414)
181+==463== by 0x4A87961: object_find_and_run (bus-objects.c:1323)
182+==463== by 0x4A87FEE: bus_process_object (bus-objects.c:1443)
183+==463== by 0x4AA3434: process_message (sd-bus.c:2964)
184+==463== by 0x4AA3623: process_running (sd-bus.c:3006)
185+==463== by 0x4AA4110: bus_process_internal (sd-bus.c:3226)
186+==463== by 0x4AA41EF: sd_bus_process (sd-bus.c:3253)
187+==463== by 0x4AA5343: io_callback (sd-bus.c:3604)
188+==463== by 0x4B2DC9B: source_dispatch (sd-event.c:3512)
189+==463== by 0x4B2FB1F: sd_event_dispatch (sd-event.c:4077)
190+==463== by 0x4B2FFFA: sd_event_run (sd-event.c:4138)
191+==463== by 0x4B301D6: sd_event_loop (sd-event.c:4159)
192+==463== by 0x464A24: run (resolved.c:92)
193+==463== by 0x464B3C: main (resolved.c:99)
194+
195+Fixes #19376.
196+
197+(cherry picked from commit c856ef0457c35e9edfdbf085b69ec81c126d48e5)
198+(cherry picked from commit 89324e233eef767334d9bfe5eed96956c973c2ad)
199+---
200+ src/resolve/resolved-dns-query.c | 42 ++++++++++++++++++++++++++++++----------
201+ 1 file changed, 32 insertions(+), 10 deletions(-)
202+
203+diff --git a/src/resolve/resolved-dns-query.c b/src/resolve/resolved-dns-query.c
204+index f6ff3b5..6f6f30d 100644
205+--- a/src/resolve/resolved-dns-query.c
206++++ b/src/resolve/resolved-dns-query.c
207+@@ -43,6 +43,8 @@ static void dns_query_candidate_stop(DnsQueryCandidate *c) {
208+
209+ assert(c);
210+
211++ /* Detach all the DnsTransactions attached to this query */
212++
213+ while ((t = set_steal_first(c->transactions))) {
214+ set_remove(t->notify_query_candidates, c);
215+ set_remove(t->notify_query_candidates_done, c);
216+@@ -50,21 +52,34 @@ static void dns_query_candidate_stop(DnsQueryCandidate *c) {
217+ }
218+ }
219+
220++static DnsQueryCandidate* dns_query_candidate_unlink(DnsQueryCandidate *c) {
221++ assert(c);
222++
223++ /* Detach this DnsQueryCandidate from the Query and Scope objects */
224++
225++ if (c->query) {
226++ LIST_REMOVE(candidates_by_query, c->query->candidates, c);
227++ c->query = NULL;
228++ }
229++
230++ if (c->scope) {
231++ LIST_REMOVE(candidates_by_scope, c->scope->query_candidates, c);
232++ c->scope = NULL;
233++ }
234++
235++ return c;
236++}
237++
238+ static DnsQueryCandidate* dns_query_candidate_free(DnsQueryCandidate *c) {
239+ if (!c)
240+ return NULL;
241+
242+ dns_query_candidate_stop(c);
243++ dns_query_candidate_unlink(c);
244+
245+ set_free(c->transactions);
246+ dns_search_domain_unref(c->search_domain);
247+
248+- if (c->query)
249+- LIST_REMOVE(candidates_by_query, c->query->candidates, c);
250+-
251+- if (c->scope)
252+- LIST_REMOVE(candidates_by_scope, c->scope->query_candidates, c);
253+-
254+ return mfree(c);
255+ }
256+
257+@@ -103,6 +118,7 @@ static int dns_query_candidate_add_transaction(DnsQueryCandidate *c, DnsResource
258+
259+ assert(c);
260+ assert(key);
261++ assert(c->query); /* We shan't add transactions to a candidate that has been detached already */
262+
263+ t = dns_scope_find_transaction(c->scope, key, true);
264+ if (!t) {
265+@@ -211,6 +227,7 @@ static int dns_query_candidate_setup_transactions(DnsQueryCandidate *c) {
266+ int n = 0, r;
267+
268+ assert(c);
269++ assert(c->query); /* We shan't add transactions to a candidate that has been detached already */
270+
271+ dns_query_candidate_stop(c);
272+
273+@@ -253,6 +270,9 @@ void dns_query_candidate_notify(DnsQueryCandidate *c) {
274+
275+ assert(c);
276+
277++ if (!c->query) /* This candidate has been abandoned, do nothing. */
278++ return;
279++
280+ state = dns_query_candidate_state(c);
281+
282+ if (DNS_TRANSACTION_IS_LIVE(state))
283+@@ -303,11 +323,13 @@ static void dns_query_stop(DnsQuery *q) {
284+ dns_query_candidate_stop(c);
285+ }
286+
287+-static void dns_query_unref_candidates(DnsQuery *q) {
288++static void dns_query_unlink_candidates(DnsQuery *q) {
289+ assert(q);
290+
291+ while (q->candidates)
292+- dns_query_candidate_unref(q->candidates);
293++ /* Here we drop *our* references to each of the candidates. If we had the only reference, the
294++ * DnsQueryCandidate object will be freed. */
295++ dns_query_candidate_unref(dns_query_candidate_unlink(q->candidates));
296+ }
297+
298+ static void dns_query_reset_answer(DnsQuery *q) {
299+@@ -336,7 +358,7 @@ DnsQuery *dns_query_free(DnsQuery *q) {
300+ LIST_REMOVE(auxiliary_queries, q->auxiliary_for->auxiliary_queries, q);
301+ }
302+
303+- dns_query_unref_candidates(q);
304++ dns_query_unlink_candidates(q);
305+
306+ dns_question_unref(q->question_idna);
307+ dns_question_unref(q->question_utf8);
308+@@ -932,7 +954,7 @@ static int dns_query_cname_redirect(DnsQuery *q, const DnsResourceRecord *cname)
309+ dns_question_unref(q->question_utf8);
310+ q->question_utf8 = TAKE_PTR(nq_utf8);
311+
312+- dns_query_unref_candidates(q);
313++ dns_query_unlink_candidates(q);
314+ dns_query_reset_answer(q);
315+
316+ q->state = DNS_TRANSACTION_NULL;
317diff --git a/debian/patches/series b/debian/patches/series
318index f680ae6..8ae5b7b 100644
319--- a/debian/patches/series
320+++ b/debian/patches/series
321@@ -96,8 +96,9 @@ lp1891215/0003-fs-util-rename-conservative_rename-conservative_rena.patch
322 lp1891215/0004-fs-util-make-sure-conservative_renameat-properly-det.patch
323 lp1914740-network-enable-DHCP-broadcast-flag-if-required-by-in.patch
324 lp1934981-correct-suspend-then-sleep-string.patch
325-lp1934221-resolved-disable-event-sources-before-unreffing-them.patch
326 CVE-2020-13529.patch
327 CVE-2021-33910.patch
328 lp1934147/0001-cgroup-do-catchup-for-unit-cgroup-inotify-watch-file.patch
329 lp1934147/0002-core-Make-sure-cgroup_oom_queue-is-flushed-on-manage.patch
330+resolved-disable-event-sources-before-unreffing-them.patch
331+resolved-fix-braino-with-reference-counting-and-linked-li.patch

Subscribers

People subscribed via source and target branches