Merge ~rafaeldtinoco/ubuntu/+source/haproxy:lp1894879-focal into ubuntu/+source/haproxy:ubuntu/focal-devel

Proposed by Rafael David Tinoco
Status: Merged
Approved by: Rafael David Tinoco
Approved revision: a257f0359b18685aaa3026245b24df3b7c9d6f1b
Merged at revision: a257f0359b18685aaa3026245b24df3b7c9d6f1b
Proposed branch: ~rafaeldtinoco/ubuntu/+source/haproxy:lp1894879-focal
Merge into: ubuntu/+source/haproxy:ubuntu/focal-devel
Diff against target: 351 lines (+305/-1)
6 files modified
debian/changelog (+10/-0)
debian/control (+2/-1)
debian/patches/lp1894879-BUG-CRITICAL-dns-Make-the-do-resolve-action-thread-safe.patch (+132/-0)
debian/patches/lp1894879-BUG-MEDIUM-dns-Dont-yield-in-do-resolve-action-on-a-final.patch (+106/-0)
debian/patches/lp1894879-BUG-MEDIUM-dns-Release-answer-items-when-a-DNS-resolution-is-freed.patch (+51/-0)
debian/patches/series (+4/-0)
Reviewer Review Type Date Requested Status
Rafael David Tinoco Pending
Review via email: mp+390625@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Rafael David Tinoco (rafaeldtinoco) wrote :

$ git push pkg upload/2.0.13-2ubuntu0.1
Counting objects: 17, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (17/17), done.
Writing objects: 100% (17/17), 6.47 KiB | 602.00 KiB/s, done.
Total 17 (delta 9), reused 0 (delta 0)
To ssh://git.launchpad.net/ubuntu/+source/haproxy
 * [new tag] upload/2.0.13-2ubuntu0.1 -> upload/2.0.13-2ubuntu0.1

$ debdiff *.dsc 2>&1 | diffstat -l | grep -v gpg
changelog
control
patches/lp1894879-BUG-CRITICAL-dns-Make-the-do-resolve-action-thread-safe.patch
patches/lp1894879-BUG-MEDIUM-dns-Dont-yield-in-do-resolve-action-on-a-final.patch
patches/lp1894879-BUG-MEDIUM-dns-Release-answer-items-when-a-DNS-resolution-is-freed.patch
patches/series

$ dput ubuntu haproxy_2.0.13-2ubuntu0.1_source.changes
Checking signature on .changes
Uploading to ubuntu (via ftp to upload.ubuntu.com):
  Uploading haproxy_2.0.13-2ubuntu0.1.dsc: done.
  Uploading haproxy_2.0.13-2ubuntu0.1.debian.tar.xz: done.
  Uploading haproxy_2.0.13-2ubuntu0.1_source.buildinfo: done.
  Uploading haproxy_2.0.13-2ubuntu0.1_source.changes: done.
Successfully uploaded packages.

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 5c9fe8b..35cd7fb 100644
3--- a/debian/changelog
4+++ b/debian/changelog
5@@ -1,3 +1,13 @@
6+haproxy (2.0.13-2ubuntu0.1) focal; urgency=medium
7+
8+ * Backport dns related fixes from git to resolve crashes when
9+ using do-resolve action (LP: #1894879)
10+ - BUG/CRITICAL: dns: Make the do-resolve action thread safe
11+ - BUG/MEDIUM: dns: Release answer items when a DNS resolution is freed
12+ - BUG/MEDIUM: dns: Don't yield in do resolve action on a final
13+
14+ -- Simon Deziel <simon@sdeziel.info> Tue, 08 Sep 2020 17:16:14 +0000
15+
16 haproxy (2.0.13-2) unstable; urgency=medium
17
18 * d/dconv: replace cgi.escape by html.escape. Closes: #951416.
19diff --git a/debian/control b/debian/control
20index cc08457..05a48d5 100644
21--- a/debian/control
22+++ b/debian/control
23@@ -1,7 +1,8 @@
24 Source: haproxy
25 Section: net
26 Priority: optional
27-Maintainer: Debian HAProxy Maintainers <haproxy@tracker.debian.org>
28+Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
29+XSBC-Original-Maintainer: Debian HAProxy Maintainers <haproxy@tracker.debian.org>
30 Uploaders: Apollon Oikonomopoulos <apoikos@debian.org>,
31 Prach Pongpanich <prach@debian.org>,
32 Vincent Bernat <bernat@debian.org>
33diff --git a/debian/patches/lp1894879-BUG-CRITICAL-dns-Make-the-do-resolve-action-thread-safe.patch b/debian/patches/lp1894879-BUG-CRITICAL-dns-Make-the-do-resolve-action-thread-safe.patch
34new file mode 100644
35index 0000000..e9e6edc
36--- /dev/null
37+++ b/debian/patches/lp1894879-BUG-CRITICAL-dns-Make-the-do-resolve-action-thread-safe.patch
38@@ -0,0 +1,132 @@
39+From ef131aee357478c45d547abcb0ab21c2a191f578 Mon Sep 17 00:00:00 2001
40+From: Christopher Faulet <cfaulet@haproxy.com>
41+Date: Wed, 22 Jul 2020 11:46:32 +0200
42+Subject: [PATCH] BUG/MAJOR: dns: Make the do-resolve action thread-safe
43+
44+The do-resolve HTTP action, performing a DNS resolution of a sample expression
45+output, is not thread-safe at all. The resolver object used to do the resolution
46+must be locked when the action is executed or when the stream is released
47+because its curr or wait resolution lists and the requester list inside a
48+resolution are updated. It is also important to not wake up a released stream
49+(with a destroyed task).
50+
51+Of course, because of this bug, various kind of crashes may be observed.
52+
53+This patch should fix the issue #236. It must be backported as far as 2.0.
54+
55+(cherry picked from commit 5098a08c2fafb0d9513996729d2a30c9785378f3)
56+Signed-off-by: Willy Tarreau <w@1wt.eu>
57+(cherry picked from commit 99f4623952cbbad2bcae451abdd0f3133bcbe75c)
58+Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
59+(cherry picked from commit 6e5861d72fe1e3c9d34b591d6f77ffd28ddde197)
60+Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
61+---
62+ src/dns.c | 36 +++++++++++++++++++++++++++---------
63+ src/stream.c | 4 ++++
64+ 2 files changed, 31 insertions(+), 9 deletions(-)
65+
66+diff --git a/src/dns.c b/src/dns.c
67+index 282fa92..40e29ad 100644
68+--- a/src/dns.c
69++++ b/src/dns.c
70+@@ -2162,14 +2162,23 @@ enum act_return dns_action_do_resolve(struct act_rule *rule, struct proxy *px,
71+ struct dns_requester *req;
72+ struct dns_resolvers *resolvers;
73+ struct dns_resolution *res;
74+- int exp;
75++ int exp, locked = 0;
76++ enum act_return ret = ACT_RET_CONT;
77++
78++ resolvers = rule->arg.dns.resolvers;
79+
80+ /* we have a response to our DNS resolution */
81+ use_cache:
82+ if (s->dns_ctx.dns_requester && s->dns_ctx.dns_requester->resolution != NULL) {
83+ resolution = s->dns_ctx.dns_requester->resolution;
84++ if (!locked) {
85++ HA_SPIN_LOCK(DNS_LOCK, &resolvers->lock);
86++ locked = 1;
87++ }
88++
89+ if (resolution->step == RSLV_STEP_RUNNING) {
90+- return ACT_RET_YIELD;
91++ ret = ACT_RET_YIELD;
92++ goto end;
93+ }
94+ if (resolution->step == RSLV_STEP_NONE) {
95+ /* We update the variable only if we have a valid response. */
96+@@ -2211,29 +2220,33 @@ enum act_return dns_action_do_resolve(struct act_rule *rule, struct proxy *px,
97+ pool_free(dns_requester_pool, s->dns_ctx.dns_requester);
98+ s->dns_ctx.dns_requester = NULL;
99+
100+- return ACT_RET_CONT;
101++ goto end;
102+ }
103+
104+ /* need to configure and start a new DNS resolution */
105+ smp = sample_fetch_as_type(px, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, rule->arg.dns.expr, SMP_T_STR);
106+ if (smp == NULL)
107+- return ACT_RET_CONT;
108++ goto end;
109+
110+ fqdn = smp->data.u.str.area;
111+ if (action_prepare_for_resolution(s, fqdn) == -1)
112+- return ACT_RET_ERR;
113++ goto end; /* on error, ignore the action */
114+
115+ s->dns_ctx.parent = rule;
116++
117++ HA_SPIN_LOCK(DNS_LOCK, &resolvers->lock);
118++ locked = 1;
119++
120+ dns_link_resolution(s, OBJ_TYPE_STREAM, 0);
121+
122+ /* Check if there is a fresh enough response in the cache of our associated resolution */
123+ req = s->dns_ctx.dns_requester;
124+ if (!req || !req->resolution) {
125+ dns_trigger_resolution(s->dns_ctx.dns_requester);
126+- return ACT_RET_YIELD;
127++ ret = ACT_RET_YIELD;
128++ goto end;
129+ }
130+- res = req->resolution;
131+- resolvers = res->resolvers;
132++ res = req->resolution;
133+
134+ exp = tick_add(res->last_resolution, resolvers->hold.valid);
135+ if (resolvers->t && res->status == RSLV_STATUS_VALID && tick_isset(res->last_resolution)
136+@@ -2242,7 +2255,12 @@ enum act_return dns_action_do_resolve(struct act_rule *rule, struct proxy *px,
137+ }
138+
139+ dns_trigger_resolution(s->dns_ctx.dns_requester);
140+- return ACT_RET_YIELD;
141++ ret = ACT_RET_YIELD;
142++
143++ end:
144++ if (locked)
145++ HA_SPIN_UNLOCK(DNS_LOCK, &resolvers->lock);
146++ return ret;
147+ }
148+
149+
150+diff --git a/src/stream.c b/src/stream.c
151+index 080189e..2eb7cfa 100644
152+--- a/src/stream.c
153++++ b/src/stream.c
154+@@ -435,9 +435,13 @@ static void stream_free(struct stream *s)
155+ }
156+
157+ if (s->dns_ctx.dns_requester) {
158++ __decl_hathreads(struct dns_resolvers *resolvers = s->dns_ctx.parent->arg.dns.resolvers);
159++
160++ HA_SPIN_LOCK(DNS_LOCK, &resolvers->lock);
161+ free(s->dns_ctx.hostname_dn); s->dns_ctx.hostname_dn = NULL;
162+ s->dns_ctx.hostname_dn_len = 0;
163+ dns_unlink_resolution(s->dns_ctx.dns_requester);
164++ HA_SPIN_UNLOCK(DNS_LOCK, &resolvers->lock);
165+
166+ pool_free(dns_requester_pool, s->dns_ctx.dns_requester);
167+ s->dns_ctx.dns_requester = NULL;
168+--
169+1.7.10.4
170+
171diff --git a/debian/patches/lp1894879-BUG-MEDIUM-dns-Dont-yield-in-do-resolve-action-on-a-final.patch b/debian/patches/lp1894879-BUG-MEDIUM-dns-Dont-yield-in-do-resolve-action-on-a-final.patch
172new file mode 100644
173index 0000000..34a6a37
174--- /dev/null
175+++ b/debian/patches/lp1894879-BUG-MEDIUM-dns-Dont-yield-in-do-resolve-action-on-a-final.patch
176@@ -0,0 +1,106 @@
177+From 74d704f2f36945d60f1ff7ea75dbfe3f40508861 Mon Sep 17 00:00:00 2001
178+From: Christopher Faulet <cfaulet@haproxy.com>
179+Date: Tue, 28 Jul 2020 10:21:54 +0200
180+Subject: [PATCH] BUG/MEDIUM: dns: Don't yield in do-resolve action on a final
181+ evaluation
182+
183+When an action is evaluated, flags are passed to know if it is the first call
184+(ACT_OPT_FIRST) and if it must be the last one (ACT_OPT_FINAL). For the
185+do-resolve DNS action, the ACT_OPT_FINAL flag must be handled because the
186+action may yield. It must never yield when this flag is set. Otherwise, it may
187+lead to a wakeup loop of the stream because the inspected-delay of a tcp-request
188+content ruleset was reached without stopping the rules evaluation.
189+
190+This patch is related to the issue #222. It must be backported as far as 2.0.
191+
192+(cherry picked from commit 385101e53816dc1b7bc1fc957adc512ce8a07cb4)
193+Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
194+(cherry picked from commit 5c038f759959adf95b4b347aba9d97e60ab87e93)
195+Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
196+(cherry picked from commit af018c4865400dda4553a732df4c43751a4ff88c)
197+Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
198+---
199+ src/dns.c | 39 +++++++++++++++++++++------------------
200+ 1 file changed, 21 insertions(+), 18 deletions(-)
201+
202+diff --git a/src/dns.c b/src/dns.c
203+index 18e64d9..095040e 100644
204+--- a/src/dns.c
205++++ b/src/dns.c
206+@@ -2182,10 +2182,8 @@ enum act_return dns_action_do_resolve(struct act_rule *rule, struct proxy *px,
207+ locked = 1;
208+ }
209+
210+- if (resolution->step == RSLV_STEP_RUNNING) {
211+- ret = ACT_RET_YIELD;
212+- goto end;
213+- }
214++ if (resolution->step == RSLV_STEP_RUNNING)
215++ goto yield;
216+ if (resolution->step == RSLV_STEP_NONE) {
217+ /* We update the variable only if we have a valid response. */
218+ if (resolution->status == RSLV_STATUS_VALID) {
219+@@ -2219,14 +2217,7 @@ enum act_return dns_action_do_resolve(struct act_rule *rule, struct proxy *px,
220+ }
221+ }
222+
223+- free(s->dns_ctx.hostname_dn); s->dns_ctx.hostname_dn = NULL;
224+- s->dns_ctx.hostname_dn_len = 0;
225+- dns_unlink_resolution(s->dns_ctx.dns_requester);
226+-
227+- pool_free(dns_requester_pool, s->dns_ctx.dns_requester);
228+- s->dns_ctx.dns_requester = NULL;
229+-
230+- goto end;
231++ goto release_requester;
232+ }
233+
234+ /* need to configure and start a new DNS resolution */
235+@@ -2247,26 +2238,38 @@ enum act_return dns_action_do_resolve(struct act_rule *rule, struct proxy *px,
236+
237+ /* Check if there is a fresh enough response in the cache of our associated resolution */
238+ req = s->dns_ctx.dns_requester;
239+- if (!req || !req->resolution) {
240+- dns_trigger_resolution(s->dns_ctx.dns_requester);
241+- ret = ACT_RET_YIELD;
242+- goto end;
243+- }
244++ if (!req || !req->resolution)
245++ goto release_requester; /* on error, ignore the action */
246+ res = req->resolution;
247+
248+ exp = tick_add(res->last_resolution, resolvers->hold.valid);
249+ if (resolvers->t && res->status == RSLV_STATUS_VALID && tick_isset(res->last_resolution)
250+- && !tick_is_expired(exp, now_ms)) {
251++ && !tick_is_expired(exp, now_ms)) {
252+ goto use_cache;
253+ }
254+
255+ dns_trigger_resolution(s->dns_ctx.dns_requester);
256++
257++ yield:
258++ if (flags & ACT_FLAG_FINAL)
259++ goto release_requester;
260+ ret = ACT_RET_YIELD;
261+
262+ end:
263+ if (locked)
264+ HA_SPIN_UNLOCK(DNS_LOCK, &resolvers->lock);
265+ return ret;
266++
267++ release_requester:
268++ free(s->dns_ctx.hostname_dn);
269++ s->dns_ctx.hostname_dn = NULL;
270++ s->dns_ctx.hostname_dn_len = 0;
271++ if (s->dns_ctx.dns_requester) {
272++ dns_unlink_resolution(s->dns_ctx.dns_requester);
273++ pool_free(dns_requester_pool, s->dns_ctx.dns_requester);
274++ s->dns_ctx.dns_requester = NULL;
275++ }
276++ goto end;
277+ }
278+
279+
280+--
281+1.7.10.4
282+
283diff --git a/debian/patches/lp1894879-BUG-MEDIUM-dns-Release-answer-items-when-a-DNS-resolution-is-freed.patch b/debian/patches/lp1894879-BUG-MEDIUM-dns-Release-answer-items-when-a-DNS-resolution-is-freed.patch
284new file mode 100644
285index 0000000..f83de45
286--- /dev/null
287+++ b/debian/patches/lp1894879-BUG-MEDIUM-dns-Release-answer-items-when-a-DNS-resolution-is-freed.patch
288@@ -0,0 +1,51 @@
289+From 39eb766825d8aad09946dfc284d4a73f610ebd64 Mon Sep 17 00:00:00 2001
290+From: Christopher Faulet <cfaulet@haproxy.com>
291+Date: Wed, 22 Jul 2020 15:55:49 +0200
292+Subject: [PATCH] BUG/MEDIUM: dns: Release answer items when a DNS resolution
293+ is freed
294+
295+When a DNS resolution is freed, the remaining items in .ar_list and .answer_list
296+are also released. It must be done to avoid a memory leak. And it is the last
297+chance to release these objects. I've honestly no idea if there is a better
298+place to release them earlier. But at least, there is no more leak.
299+
300+This patch should solve the issue #222. It must be backported, at least, as far
301+as 2.0, and probably, with caution, as far as 1.8 or 1.7.
302+
303+(cherry picked from commit 010ab35a9118daf17a670fb2b42e40447f967f7c)
304+Signed-off-by: Willy Tarreau <w@1wt.eu>
305+(cherry picked from commit c58ac80d00284886b108b209a5bf993de5ab38ed)
306+Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
307+(cherry picked from commit 81120e6ea286ae3f2566959167fb56a7d1f0de19)
308+Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
309+---
310+ src/dns.c | 6 ++++++
311+ 1 file changed, 6 insertions(+)
312+
313+diff --git a/src/dns.c b/src/dns.c
314+index 40e29ad..18e64d9 100644
315+--- a/src/dns.c
316++++ b/src/dns.c
317+@@ -1336,6 +1336,7 @@ static struct dns_resolution *dns_pick_resolution(struct dns_resolvers *resolver
318+ static void dns_free_resolution(struct dns_resolution *resolution)
319+ {
320+ struct dns_requester *req, *reqback;
321++ struct dns_answer_item *item, *itemback;
322+
323+ /* clean up configuration */
324+ dns_reset_resolution(resolution);
325+@@ -1347,6 +1348,11 @@ static void dns_free_resolution(struct dns_resolution *resolution)
326+ req->resolution = NULL;
327+ }
328+
329++ list_for_each_entry_safe(item, itemback, &resolution->response.answer_list, list) {
330++ LIST_DEL(&item->list);
331++ pool_free(dns_answer_item_pool, item);
332++ }
333++
334+ LIST_DEL(&resolution->list);
335+ pool_free(dns_resolution_pool, resolution);
336+ }
337+--
338+1.7.10.4
339+
340diff --git a/debian/patches/series b/debian/patches/series
341index b57f722..c8fe75d 100644
342--- a/debian/patches/series
343+++ b/debian/patches/series
344@@ -7,3 +7,7 @@ haproxy.service-add-documentation.patch
345
346 # applied during the build process:
347 # debianize-dconv.patch
348+
349+lp1894879-BUG-CRITICAL-dns-Make-the-do-resolve-action-thread-safe.patch
350+lp1894879-BUG-MEDIUM-dns-Release-answer-items-when-a-DNS-resolution-is-freed.patch
351+lp1894879-BUG-MEDIUM-dns-Dont-yield-in-do-resolve-action-on-a-final.patch

Subscribers

People subscribed via source and target branches