1 commit 3c42f13badd149c9c3152d7b2e653bde5da7c17a
2 Author: Willy Tarreau <w@1wt.eu>
3 Date: Tue Aug 21 14:50:44 2018 +0200
5 BUG/MEDIUM: cli/threads: protect all "proxy" commands against concurrent updates
7 The proxy-related commands like "{enable|disable|shutdown} frontend",
8 "{enable|disable} dynamic-cookie", "set dynamic-cookie-key" were not
9 protected against concurrent accesses making their use dangerous with
12 This patch must be backported to 1.8.
14 (cherry picked from commit a275a3710eaa365150fe89e2e7a8fbdce87bb30e)
15 Signed-off-by: Willy Tarreau <w@1wt.eu>
17 diff --git a/src/proxy.c b/src/proxy.c
18 index 4437b703..8926ba8b 100644
21 @@ -1560,7 +1560,10 @@ static int cli_io_handler_show_backend(struct appctx *appctx)
25 -/* Parses the "enable dynamic-cookies backend" directive, it always returns 1 */
26 +/* Parses the "enable dynamic-cookies backend" directive, it always returns 1.
28 + * Grabs the proxy lock and each server's lock.
30 static int cli_parse_enable_dyncookie_backend(char **args, struct appctx *appctx, void *private)
33 @@ -1573,15 +1576,25 @@ static int cli_parse_enable_dyncookie_backend(char **args, struct appctx *appctx
37 + HA_SPIN_LOCK(PROXY_LOCK, &px->lock);
39 px->ck_opts |= PR_CK_DYNAMIC;
41 - for (s = px->srv; s != NULL; s = s->next)
42 + for (s = px->srv; s != NULL; s = s->next) {
43 + HA_SPIN_LOCK(SERVER_LOCK, &s->lock);
45 + HA_SPIN_UNLOCK(SERVER_LOCK, &s->lock);
48 + HA_SPIN_UNLOCK(PROXY_LOCK, &px->lock);
53 -/* Parses the "disable dynamic-cookies backend" directive, it always returns 1 */
54 +/* Parses the "disable dynamic-cookies backend" directive, it always returns 1.
56 + * Grabs the proxy lock and each server's lock.
58 static int cli_parse_disable_dyncookie_backend(char **args, struct appctx *appctx, void *private)
61 @@ -1594,19 +1607,28 @@ static int cli_parse_disable_dyncookie_backend(char **args, struct appctx *appct
65 + HA_SPIN_LOCK(PROXY_LOCK, &px->lock);
67 px->ck_opts &= ~PR_CK_DYNAMIC;
69 for (s = px->srv; s != NULL; s = s->next) {
70 + HA_SPIN_LOCK(SERVER_LOCK, &s->lock);
71 if (!(s->flags & SRV_F_COOKIESET)) {
75 + HA_SPIN_UNLOCK(SERVER_LOCK, &s->lock);
78 + HA_SPIN_UNLOCK(PROXY_LOCK, &px->lock);
83 -/* Parses the "set dynamic-cookie-key backend" directive, it always returns 1 */
84 +/* Parses the "set dynamic-cookie-key backend" directive, it always returns 1.
86 + * Grabs the proxy lock and each server's lock.
88 static int cli_parse_set_dyncookie_key_backend(char **args, struct appctx *appctx, void *private)
91 @@ -1634,16 +1656,27 @@ static int cli_parse_set_dyncookie_key_backend(char **args, struct appctx *appct
92 appctx->st0 = CLI_ST_PRINT;
96 + HA_SPIN_LOCK(PROXY_LOCK, &px->lock);
98 free(px->dyncookie_key);
99 px->dyncookie_key = newkey;
101 - for (s = px->srv; s != NULL; s = s->next)
102 + for (s = px->srv; s != NULL; s = s->next) {
103 + HA_SPIN_LOCK(SERVER_LOCK, &s->lock);
104 srv_set_dyncookie(s);
105 + HA_SPIN_UNLOCK(SERVER_LOCK, &s->lock);
108 + HA_SPIN_UNLOCK(PROXY_LOCK, &px->lock);
113 -/* Parses the "set maxconn frontend" directive, it always returns 1 */
114 +/* Parses the "set maxconn frontend" directive, it always returns 1.
116 + * Grabs the proxy lock.
118 static int cli_parse_set_maxconn_frontend(char **args, struct appctx *appctx, void *private)
121 @@ -1675,6 +1708,8 @@ static int cli_parse_set_maxconn_frontend(char **args, struct appctx *appctx, vo
122 /* OK, the value is fine, so we assign it to the proxy and to all of
123 * its listeners. The blocked ones will be dequeued.
125 + HA_SPIN_LOCK(PROXY_LOCK, &px->lock);
128 list_for_each_entry(l, &px->conf.listeners, by_fe) {
130 @@ -1685,10 +1720,15 @@ static int cli_parse_set_maxconn_frontend(char **args, struct appctx *appctx, vo
131 if (px->maxconn > px->feconn && !LIST_ISEMPTY(&px->listener_queue))
132 dequeue_all_listeners(&px->listener_queue);
134 + HA_SPIN_UNLOCK(PROXY_LOCK, &px->lock);
139 -/* Parses the "shutdown frontend" directive, it always returns 1 */
140 +/* Parses the "shutdown frontend" directive, it always returns 1.
142 + * Grabs the proxy lock.
144 static int cli_parse_shutdown_frontend(char **args, struct appctx *appctx, void *private)
147 @@ -1711,14 +1751,22 @@ static int cli_parse_shutdown_frontend(char **args, struct appctx *appctx, void
148 px->id, px->fe_counters.cum_conn, px->be_counters.cum_conn);
149 send_log(px, LOG_WARNING, "Proxy %s stopped (FE: %lld conns, BE: %lld conns).\n",
150 px->id, px->fe_counters.cum_conn, px->be_counters.cum_conn);
152 + HA_SPIN_LOCK(PROXY_LOCK, &px->lock);
154 + HA_SPIN_UNLOCK(PROXY_LOCK, &px->lock);
159 -/* Parses the "disable frontend" directive, it always returns 1 */
160 +/* Parses the "disable frontend" directive, it always returns 1.
162 + * Grabs the proxy lock.
164 static int cli_parse_disable_frontend(char **args, struct appctx *appctx, void *private)
169 if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
171 @@ -1741,7 +1789,11 @@ static int cli_parse_disable_frontend(char **args, struct appctx *appctx, void *
175 - if (!pause_proxy(px)) {
176 + HA_SPIN_LOCK(PROXY_LOCK, &px->lock);
177 + ret = pause_proxy(px);
178 + HA_SPIN_UNLOCK(PROXY_LOCK, &px->lock);
181 appctx->ctx.cli.severity = LOG_ERR;
182 appctx->ctx.cli.msg = "Failed to pause frontend, check logs for precise cause.\n";
183 appctx->st0 = CLI_ST_PRINT;
184 @@ -1750,10 +1802,14 @@ static int cli_parse_disable_frontend(char **args, struct appctx *appctx, void *
188 -/* Parses the "enable frontend" directive, it always returns 1 */
189 +/* Parses the "enable frontend" directive, it always returns 1.
191 + * Grabs the proxy lock.
193 static int cli_parse_enable_frontend(char **args, struct appctx *appctx, void *private)
198 if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
200 @@ -1776,7 +1832,11 @@ static int cli_parse_enable_frontend(char **args, struct appctx *appctx, void *p
204 - if (!resume_proxy(px)) {
205 + HA_SPIN_LOCK(PROXY_LOCK, &px->lock);
206 + ret = resume_proxy(px);
207 + HA_SPIN_UNLOCK(PROXY_LOCK, &px->lock);
210 appctx->ctx.cli.severity = LOG_ERR;
211 appctx->ctx.cli.msg = "Failed to resume frontend, check logs for precise cause (port conflict?).\n";
212 appctx->st0 = CLI_ST_PRINT;