385db51c5c610719c7e7e109a027c1f7d28bd68e
[openwrt-packages.git] /
1 commit 3c42f13badd149c9c3152d7b2e653bde5da7c17a
2 Author: Willy Tarreau <w@1wt.eu>
3 Date:   Tue Aug 21 14:50:44 2018 +0200
4
5     BUG/MEDIUM: cli/threads: protect all "proxy" commands against concurrent updates
6     
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
10     threads.
11     
12     This patch must be backported to 1.8.
13     
14     (cherry picked from commit a275a3710eaa365150fe89e2e7a8fbdce87bb30e)
15     Signed-off-by: Willy Tarreau <w@1wt.eu>
16
17 diff --git a/src/proxy.c b/src/proxy.c
18 index 4437b703..8926ba8b 100644
19 --- a/src/proxy.c
20 +++ b/src/proxy.c
21 @@ -1560,7 +1560,10 @@ static int cli_io_handler_show_backend(struct appctx *appctx)
22         return 1;
23  }
24  
25 -/* Parses the "enable dynamic-cookies backend" directive, it always returns 1 */
26 +/* Parses the "enable dynamic-cookies backend" directive, it always returns 1.
27 + *
28 + * Grabs the proxy lock and each server's lock.
29 + */
30  static int cli_parse_enable_dyncookie_backend(char **args, struct appctx *appctx, void *private)
31  {
32         struct proxy *px;
33 @@ -1573,15 +1576,25 @@ static int cli_parse_enable_dyncookie_backend(char **args, struct appctx *appctx
34         if (!px)
35                 return 1;
36  
37 +       HA_SPIN_LOCK(PROXY_LOCK, &px->lock);
38 +
39         px->ck_opts |= PR_CK_DYNAMIC;
40  
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);
44                 srv_set_dyncookie(s);
45 +               HA_SPIN_UNLOCK(SERVER_LOCK, &s->lock);
46 +       }
47 +
48 +       HA_SPIN_UNLOCK(PROXY_LOCK, &px->lock);
49  
50         return 1;
51  }
52  
53 -/* Parses the "disable dynamic-cookies backend" directive, it always returns 1 */
54 +/* Parses the "disable dynamic-cookies backend" directive, it always returns 1.
55 + *
56 + * Grabs the proxy lock and each server's lock.
57 + */
58  static int cli_parse_disable_dyncookie_backend(char **args, struct appctx *appctx, void *private)
59  {
60         struct proxy *px;
61 @@ -1594,19 +1607,28 @@ static int cli_parse_disable_dyncookie_backend(char **args, struct appctx *appct
62         if (!px)
63                 return 1;
64  
65 +       HA_SPIN_LOCK(PROXY_LOCK, &px->lock);
66 +
67         px->ck_opts &= ~PR_CK_DYNAMIC;
68  
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)) {
72                         free(s->cookie);
73                         s->cookie = NULL;
74                 }
75 +               HA_SPIN_UNLOCK(SERVER_LOCK, &s->lock);
76         }
77  
78 +       HA_SPIN_UNLOCK(PROXY_LOCK, &px->lock);
79 +
80         return 1;
81  }
82  
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.
85 + *
86 + * Grabs the proxy lock and each server's lock.
87 + */
88  static int cli_parse_set_dyncookie_key_backend(char **args, struct appctx *appctx, void *private)
89  {
90         struct proxy *px;
91 @@ -1634,16 +1656,27 @@ static int cli_parse_set_dyncookie_key_backend(char **args, struct appctx *appct
92                 appctx->st0 = CLI_ST_PRINT;
93                 return 1;
94         }
95 +
96 +       HA_SPIN_LOCK(PROXY_LOCK, &px->lock);
97 +
98         free(px->dyncookie_key);
99         px->dyncookie_key = newkey;
100  
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);
106 +       }
107 +
108 +       HA_SPIN_UNLOCK(PROXY_LOCK, &px->lock);
109  
110         return 1;
111  }
112  
113 -/* Parses the "set maxconn frontend" directive, it always returns 1 */
114 +/* Parses the "set maxconn frontend" directive, it always returns 1.
115 + *
116 + * Grabs the proxy lock.
117 + */
118  static int cli_parse_set_maxconn_frontend(char **args, struct appctx *appctx, void *private)
119  {
120         struct proxy *px;
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.
124          */
125 +       HA_SPIN_LOCK(PROXY_LOCK, &px->lock);
126 +
127         px->maxconn = v;
128         list_for_each_entry(l, &px->conf.listeners, by_fe) {
129                 l->maxconn = v;
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);
133  
134 +       HA_SPIN_UNLOCK(PROXY_LOCK, &px->lock);
135 +
136         return 1;
137  }
138  
139 -/* Parses the "shutdown frontend" directive, it always returns 1 */
140 +/* Parses the "shutdown frontend" directive, it always returns 1.
141 + *
142 + * Grabs the proxy lock.
143 + */
144  static int cli_parse_shutdown_frontend(char **args, struct appctx *appctx, void *private)
145  {
146         struct proxy *px;
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);
151 +
152 +       HA_SPIN_LOCK(PROXY_LOCK, &px->lock);
153         stop_proxy(px);
154 +       HA_SPIN_UNLOCK(PROXY_LOCK, &px->lock);
155 +
156         return 1;
157  }
158  
159 -/* Parses the "disable frontend" directive, it always returns 1 */
160 +/* Parses the "disable frontend" directive, it always returns 1.
161 + *
162 + * Grabs the proxy lock.
163 + */
164  static int cli_parse_disable_frontend(char **args, struct appctx *appctx, void *private)
165  {
166         struct proxy *px;
167 +       int ret;
168  
169         if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
170                 return 1;
171 @@ -1741,7 +1789,11 @@ static int cli_parse_disable_frontend(char **args, struct appctx *appctx, void *
172                 return 1;
173         }
174  
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);
179 +
180 +       if (!ret) {
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 *
185         return 1;
186  }
187  
188 -/* Parses the "enable frontend" directive, it always returns 1 */
189 +/* Parses the "enable frontend" directive, it always returns 1.
190 + *
191 + * Grabs the proxy lock.
192 + */
193  static int cli_parse_enable_frontend(char **args, struct appctx *appctx, void *private)
194  {
195         struct proxy *px;
196 +       int ret;
197  
198         if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
199                 return 1;
200 @@ -1776,7 +1832,11 @@ static int cli_parse_enable_frontend(char **args, struct appctx *appctx, void *p
201                 return 1;
202         }
203  
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);
208 +
209 +       if (!ret) {
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;
git clone https://git.99rst.org/PROJECT