diff options
author | Nick Leverton <nick@leverton.org> | 2016-03-17 15:15:22 +0000 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2016-03-20 23:12:28 +0000 |
commit | 7d6801c46539035ae901d245b5376a392f8f9ce2 (patch) | |
tree | 84becc2cd17922b9c4ba4d0551ceb4405d2669a2 /meta/recipes-extended/lighttpd | |
parent | 5f7b9f037172fabaa550c7509a6e69e62027d917 (diff) | |
download | poky-7d6801c46539035ae901d245b5376a392f8f9ce2.tar.gz |
lighttpd: fix /usr/lib/mod_cgi.so: undefined symbol: chunkqueue_written
lighttpd fails to load when mod_cgi is enabled at run time, with the
message "dlopen() failed for: /usr/lib/mod_cgi.so /usr/lib/mod_cgi.so:
undefined symbol: chunkqueue_written".
This is caused by a patch intended to prevent memory exhaustion by
naively streaming CGIs, aimed at upstream issue
http://redmine.lighttpd.net/issues/1264 . The patch uses internal API
functions from older versions of lighttpd which don't exist in this
version. Remove the patch, pending a better fix.
[ YOCTO #9289 ]
(From OE-Core rev: 880a346bf1bc4aa6c8569c6319c141433e13e1dd)
Signed-off-by: Nick Leverton <nick@leverton.org>
Signed-off-by: Ross Burton <ross.burton@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'meta/recipes-extended/lighttpd')
-rw-r--r-- | meta/recipes-extended/lighttpd/lighttpd/0001-mod_cgi-buffers-data-without-bound.patch | 387 | ||||
-rw-r--r-- | meta/recipes-extended/lighttpd/lighttpd_1.4.39.bb | 1 |
2 files changed, 0 insertions, 388 deletions
diff --git a/meta/recipes-extended/lighttpd/lighttpd/0001-mod_cgi-buffers-data-without-bound.patch b/meta/recipes-extended/lighttpd/lighttpd/0001-mod_cgi-buffers-data-without-bound.patch deleted file mode 100644 index a9df1744a7..0000000000 --- a/meta/recipes-extended/lighttpd/lighttpd/0001-mod_cgi-buffers-data-without-bound.patch +++ /dev/null | |||
@@ -1,387 +0,0 @@ | |||
1 | From e6ccbab5d42b110ac4f6ce1f72cb1e9ccbe4400a Mon Sep 17 00:00:00 2001 | ||
2 | From: Li xin <lixin.fnst@cn.fujitsu.com> | ||
3 | Date: Tue, 16 Jun 2015 19:02:38 +0900 | ||
4 | Subject: [PATCH] mod_cgi buffers data without bound so fix it | ||
5 | |||
6 | Upstream-Status: Submitted [http://redmine.lighttpd.net/issues/1264] | ||
7 | |||
8 | Signed-off-by: Li Xin <lixin.fnst@cn.fujitsu.com> | ||
9 | |||
10 | Update context for 1.4.36. | ||
11 | |||
12 | Signed-off-by: Kai Kang <kai.kang@windriver.com> | ||
13 | --- | ||
14 | doc/config/lighttpd.conf | 8 ++ | ||
15 | src/mod_cgi.c | 188 ++++++++++++++++++++++++++++++++++++++++++++--- | ||
16 | 2 files changed, 187 insertions(+), 9 deletions(-) | ||
17 | |||
18 | diff --git a/doc/config/lighttpd.conf b/doc/config/lighttpd.conf | ||
19 | index 60b0ae1..9c101a7 100644 | ||
20 | --- a/doc/config/lighttpd.conf | ||
21 | +++ b/doc/config/lighttpd.conf | ||
22 | @@ -375,6 +375,14 @@ server.upload-dirs = ( "/var/tmp" ) | ||
23 | ## | ||
24 | ####################################################################### | ||
25 | |||
26 | +####################################################################### | ||
27 | +## | ||
28 | +## | ||
29 | +## maximum bytes in send_raw before backing off [KByte] | ||
30 | +## cgi.high-waterlevel = 10240 | ||
31 | +## minimum bytes in send_raw to disable backoff [KByte] | ||
32 | +## cgi.low-waterlevel = 5120 | ||
33 | +####################################################################### | ||
34 | |||
35 | ####################################################################### | ||
36 | ## | ||
37 | diff --git a/src/mod_cgi.c b/src/mod_cgi.c | ||
38 | index 01b1877..7c67eb5 100644 | ||
39 | --- a/src/mod_cgi.c | ||
40 | +++ b/src/mod_cgi.c | ||
41 | @@ -38,6 +38,10 @@ | ||
42 | |||
43 | #include "version.h" | ||
44 | |||
45 | +/* for output logs */ | ||
46 | +char msgbuf[2048]; | ||
47 | + | ||
48 | + | ||
49 | enum {EOL_UNSET, EOL_N, EOL_RN}; | ||
50 | |||
51 | typedef struct { | ||
52 | @@ -53,9 +57,19 @@ typedef struct { | ||
53 | size_t size; | ||
54 | } buffer_pid_t; | ||
55 | |||
56 | +struct handler_ctx; | ||
57 | + | ||
58 | +typedef struct { | ||
59 | + struct handler_ctx **hctx; | ||
60 | + size_t used; | ||
61 | + size_t size; | ||
62 | +} buffer_ctx_t; | ||
63 | + | ||
64 | typedef struct { | ||
65 | array *cgi; | ||
66 | unsigned short execute_x_only; | ||
67 | + unsigned int high_waterlevel; /* maximum bytes in send_raw before backing off */ | ||
68 | + unsigned int low_waterlevel; /* minimum bytes in send_raw to disable backoff */ | ||
69 | } plugin_config; | ||
70 | |||
71 | typedef struct { | ||
72 | @@ -68,9 +82,11 @@ typedef struct { | ||
73 | plugin_config **config_storage; | ||
74 | |||
75 | plugin_config conf; | ||
76 | + | ||
77 | + buffer_ctx_t cgi_ctx; | ||
78 | } plugin_data; | ||
79 | |||
80 | -typedef struct { | ||
81 | +typedef struct handler_ctx { | ||
82 | pid_t pid; | ||
83 | int fd; | ||
84 | int fde_ndx; /* index into the fd-event buffer */ | ||
85 | @@ -78,11 +94,16 @@ typedef struct { | ||
86 | connection *remote_conn; /* dumb pointer */ | ||
87 | plugin_data *plugin_data; /* dumb pointer */ | ||
88 | |||
89 | + int throttling; /* 1=waiting for send_raw buffer to drain */ | ||
90 | + off_t high_waterlevel; /* maximum bytes in send_raw before backing off */ | ||
91 | + off_t low_waterlevel; /* minimum bytes in send_raw to disable backoff */ | ||
92 | + off_t bytes_in_buffer; | ||
93 | + | ||
94 | buffer *response; | ||
95 | buffer *response_header; | ||
96 | } handler_ctx; | ||
97 | |||
98 | -static handler_ctx * cgi_handler_ctx_init(void) { | ||
99 | +static handler_ctx * cgi_handler_ctx_init(plugin_data *p) { | ||
100 | handler_ctx *hctx = calloc(1, sizeof(*hctx)); | ||
101 | |||
102 | force_assert(hctx); | ||
103 | @@ -90,13 +111,26 @@ static handler_ctx * cgi_handler_ctx_init(void) { | ||
104 | hctx->response = buffer_init(); | ||
105 | hctx->response_header = buffer_init(); | ||
106 | |||
107 | + hctx->throttling = 0; | ||
108 | + hctx->high_waterlevel = (off_t)p->conf.high_waterlevel * 1024; | ||
109 | + hctx->low_waterlevel = (off_t)p->conf.low_waterlevel * 1024; | ||
110 | + if (hctx->low_waterlevel >= hctx->high_waterlevel) { | ||
111 | + hctx->low_waterlevel = hctx->high_waterlevel * 3 / 4; /* 75% */ | ||
112 | + } | ||
113 | + hctx->bytes_in_buffer = 0; | ||
114 | + | ||
115 | return hctx; | ||
116 | } | ||
117 | |||
118 | -static void cgi_handler_ctx_free(handler_ctx *hctx) { | ||
119 | +static void cgi_handler_ctx_free(server *srv, handler_ctx *hctx) { | ||
120 | buffer_free(hctx->response); | ||
121 | buffer_free(hctx->response_header); | ||
122 | |||
123 | + /* to avoid confusion */ | ||
124 | + if (hctx->throttling) { | ||
125 | + log_error_write(srv, __FILE__, __LINE__, "s", "unthrottled"); | ||
126 | + } | ||
127 | + | ||
128 | free(hctx); | ||
129 | } | ||
130 | |||
131 | @@ -154,6 +188,8 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) { | ||
132 | config_values_t cv[] = { | ||
133 | { "cgi.assign", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */ | ||
134 | { "cgi.execute-x-only", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 1 */ | ||
135 | + { "cgi.high-waterlevel", NULL, T_CONFIG_INT, T_CONFIG_SCOPE_CONNECTION }, /* 2 */ | ||
136 | + { "cgi.low-waterlevel", NULL, T_CONFIG_INT, T_CONFIG_SCOPE_CONNECTION }, /* 3 */ | ||
137 | { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET} | ||
138 | }; | ||
139 | |||
140 | @@ -169,9 +205,13 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) { | ||
141 | |||
142 | s->cgi = array_init(); | ||
143 | s->execute_x_only = 0; | ||
144 | + s->high_waterlevel = 0; /* 0 == disabled */ | ||
145 | + s->low_waterlevel = 0; | ||
146 | |||
147 | cv[0].destination = s->cgi; | ||
148 | cv[1].destination = &(s->execute_x_only); | ||
149 | + cv[2].destination = &(s->high_waterlevel); | ||
150 | + cv[3].destination = &(s->low_waterlevel); | ||
151 | |||
152 | p->config_storage[i] = s; | ||
153 | |||
154 | @@ -184,6 +224,51 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) { | ||
155 | } | ||
156 | |||
157 | |||
158 | +static void cgi_recount_bytes_in_buffer(handler_ctx *hctx) | ||
159 | +{ | ||
160 | + chunkqueue *cq = hctx->remote_conn->write_queue; | ||
161 | + hctx->bytes_in_buffer = chunkqueue_length(cq) - chunkqueue_written(cq); | ||
162 | +} | ||
163 | + | ||
164 | + | ||
165 | +static void cgi_throttling_control(server *srv, handler_ctx *hctx) | ||
166 | +{ | ||
167 | + cgi_recount_bytes_in_buffer(hctx); | ||
168 | + | ||
169 | +#ifdef DEBUG | ||
170 | + sprintf(msgbuf, "throttling=%d, chars=%llu, high=%llu, low=%llu", | ||
171 | + hctx->throttling, hctx->bytes_in_buffer, | ||
172 | + hctx->high_waterlevel, hctx->low_waterlevel); | ||
173 | + log_error_write(srv, __FILE__, __LINE__, "ss", | ||
174 | + "(debug) throttling control,", msgbuf); | ||
175 | +#endif | ||
176 | + | ||
177 | + if (hctx->throttling) { | ||
178 | + sprintf(msgbuf, "throttling; chars in queue=%llu," | ||
179 | + " low-waterlevel=%llu, high-waterlevel=%llu", | ||
180 | + hctx->bytes_in_buffer, | ||
181 | + hctx->low_waterlevel, hctx->high_waterlevel); | ||
182 | + log_error_write(srv, __FILE__, __LINE__, "s", msgbuf); | ||
183 | + if (hctx->bytes_in_buffer <= hctx->low_waterlevel) { | ||
184 | + fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN); | ||
185 | + hctx->throttling = 0; | ||
186 | + log_error_write(srv, __FILE__, __LINE__, "s", "unthrottled"); | ||
187 | + } | ||
188 | + } else { | ||
189 | + if (hctx->high_waterlevel != 0 && | ||
190 | + hctx->high_waterlevel <= hctx->bytes_in_buffer) { | ||
191 | + fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd); | ||
192 | + hctx->throttling = 1; | ||
193 | + sprintf(msgbuf, "throttled; chars in queue=%llu," | ||
194 | + " low-waterlevel=%llu, high-waterlevel=%llu", | ||
195 | + hctx->bytes_in_buffer, | ||
196 | + hctx->low_waterlevel, hctx->high_waterlevel); | ||
197 | + log_error_write(srv, __FILE__, __LINE__, "s", msgbuf); | ||
198 | + } | ||
199 | + } | ||
200 | +} | ||
201 | + | ||
202 | + | ||
203 | static int cgi_pid_add(server *srv, plugin_data *p, pid_t pid) { | ||
204 | int m = -1; | ||
205 | size_t i; | ||
206 | @@ -230,6 +315,39 @@ static int cgi_pid_del(server *srv, plugin_data *p, pid_t pid) { | ||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | + | ||
211 | +static void cgi_ctx_add(plugin_data *p, handler_ctx *hctx) { | ||
212 | + buffer_ctx_t *r = &(p->cgi_ctx); | ||
213 | + | ||
214 | + if (r->size == 0) { | ||
215 | + r->size = 16; | ||
216 | + r->hctx = malloc(sizeof(*r->hctx) * r->size); | ||
217 | + } else if (r->used == r->size) { | ||
218 | + r->size += 16; | ||
219 | + r->hctx = realloc(r->hctx, sizeof(*r->hctx) * r->size); | ||
220 | + } | ||
221 | + | ||
222 | + r->hctx[r->used++] = hctx; | ||
223 | +} | ||
224 | + | ||
225 | +static void cgi_ctx_del(plugin_data *p, handler_ctx *hctx) { | ||
226 | + size_t i; | ||
227 | + buffer_ctx_t *r = &(p->cgi_ctx); | ||
228 | + | ||
229 | + for (i = 0; i < r->used; i++) { | ||
230 | + if (r->hctx[i] == hctx) break; | ||
231 | + } | ||
232 | + | ||
233 | + if (i != r->used) { | ||
234 | + /* found */ | ||
235 | + | ||
236 | + if (i != r->used - 1) { | ||
237 | + r->hctx[i] = r->hctx[r->used - 1]; | ||
238 | + } | ||
239 | + r->used--; | ||
240 | + } | ||
241 | +} | ||
242 | + | ||
243 | static int cgi_response_parse(server *srv, connection *con, plugin_data *p, buffer *in) { | ||
244 | char *ns; | ||
245 | const char *s; | ||
246 | @@ -380,6 +498,14 @@ static int cgi_demux_response(server *srv, handler_ctx *hctx) { | ||
247 | |||
248 | buffer_commit(hctx->response, n); | ||
249 | |||
250 | +#ifdef DEBUG | ||
251 | + sprintf(msgbuf, "n=%d, bytes_out=%llu, bytes_in=%llu", n, | ||
252 | + (unsigned long long)con->write_queue->bytes_out, | ||
253 | + (unsigned long long)con->write_queue->bytes_in); | ||
254 | + log_error_write(srv, __FILE__, __LINE__, "ss", | ||
255 | + "(debug) read,", msgbuf); | ||
256 | +#endif | ||
257 | + | ||
258 | /* split header from body */ | ||
259 | |||
260 | if (con->file_started == 0) { | ||
261 | @@ -503,7 +629,20 @@ static int cgi_demux_response(server *srv, handler_ctx *hctx) { | ||
262 | } | ||
263 | } else { | ||
264 | http_chunk_append_buffer(srv, con, hctx->response); | ||
265 | +#ifdef DEBUG | ||
266 | + sprintf(msgbuf, "n=%d, bytes_out=%llu, bytes_in=%llu, limit=%llu", n, | ||
267 | + (unsigned long long)con->write_queue->bytes_out, | ||
268 | + (unsigned long long)con->write_queue->bytes_in, | ||
269 | + (unsigned long long)hctx->high_waterlevel); | ||
270 | + log_error_write(srv, __FILE__, __LINE__, | ||
271 | + "ss", "(debug) append,", msgbuf); | ||
272 | +#endif | ||
273 | joblist_append(srv, con); | ||
274 | + | ||
275 | + cgi_throttling_control(srv, hctx); | ||
276 | + if (hctx->throttling) { | ||
277 | + return FDEVENT_HANDLED_NOT_FINISHED; | ||
278 | + } | ||
279 | } | ||
280 | |||
281 | #if 0 | ||
282 | @@ -553,8 +692,9 @@ static handler_t cgi_connection_close(server *srv, handler_ctx *hctx) { | ||
283 | con->plugin_ctx[p->id] = NULL; | ||
284 | |||
285 | /* is this a good idea ? */ | ||
286 | - cgi_handler_ctx_free(hctx); | ||
287 | - | ||
288 | + cgi_ctx_del(p, hctx); | ||
289 | + cgi_handler_ctx_free(srv, hctx); | ||
290 | + | ||
291 | /* if waitpid hasn't been called by response.c yet, do it here */ | ||
292 | if (pid) { | ||
293 | /* check if the CGI-script is already gone */ | ||
294 | @@ -1105,7 +1245,8 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer * | ||
295 | con->mode = p->id; | ||
296 | buffer_reset(con->physical.path); | ||
297 | |||
298 | - hctx = cgi_handler_ctx_init(); | ||
299 | + hctx = cgi_handler_ctx_init(p); | ||
300 | + cgi_ctx_add(p, hctx); | ||
301 | |||
302 | hctx->remote_conn = con; | ||
303 | hctx->plugin_data = p; | ||
304 | @@ -1114,6 +1255,11 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer * | ||
305 | hctx->fde_ndx = -1; | ||
306 | |||
307 | con->plugin_ctx[p->id] = hctx; | ||
308 | +#ifdef DEBUG | ||
309 | + sprintf(msgbuf, "hctx=%p, con=%p", (void*)hctx, (void*)con); | ||
310 | + log_error_write(srv, __FILE__, __LINE__, "ss", | ||
311 | + "(debug) hctx generated, ", msgbuf); | ||
312 | +#endif | ||
313 | |||
314 | fdevent_register(srv->ev, hctx->fd, cgi_handle_fdevent, hctx); | ||
315 | fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN); | ||
316 | @@ -1128,7 +1274,8 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer * | ||
317 | |||
318 | close(hctx->fd); | ||
319 | |||
320 | - cgi_handler_ctx_free(hctx); | ||
321 | + cgi_ctx_del(p, hctx); | ||
322 | + cgi_handler_ctx_free(srv, hctx); | ||
323 | |||
324 | con->plugin_ctx[p->id] = NULL; | ||
325 | |||
326 | @@ -1153,6 +1300,8 @@ static int mod_cgi_patch_connection(server *srv, connection *con, plugin_data *p | ||
327 | |||
328 | PATCH(cgi); | ||
329 | PATCH(execute_x_only); | ||
330 | + PATCH(high_waterlevel); | ||
331 | + PATCH(low_waterlevel); | ||
332 | |||
333 | /* skip the first, the global context */ | ||
334 | for (i = 1; i < srv->config_context->used; i++) { | ||
335 | @@ -1170,6 +1319,10 @@ static int mod_cgi_patch_connection(server *srv, connection *con, plugin_data *p | ||
336 | PATCH(cgi); | ||
337 | } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cgi.execute-x-only"))) { | ||
338 | PATCH(execute_x_only); | ||
339 | + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cgi.high-waterlevel"))) { | ||
340 | + PATCH(high_waterlevel); | ||
341 | + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cgi.low-waterlevel"))) { | ||
342 | + PATCH(low_waterlevel); | ||
343 | } | ||
344 | } | ||
345 | } | ||
346 | @@ -1222,6 +1375,21 @@ URIHANDLER_FUNC(cgi_is_handled) { | ||
347 | TRIGGER_FUNC(cgi_trigger) { | ||
348 | plugin_data *p = p_d; | ||
349 | size_t ndx; | ||
350 | + | ||
351 | + for (ndx = 0; ndx < p->cgi_ctx.used; ndx++) { | ||
352 | + handler_ctx *hctx = p->cgi_ctx.hctx[ndx]; | ||
353 | +#ifdef DEBUG | ||
354 | + connection *con = hctx->remote_conn; | ||
355 | + | ||
356 | + sprintf(msgbuf, "hctx=%p, con=%p, bytes_in_buffer=%llu", | ||
357 | + (void*)hctx, (void*)con, | ||
358 | + (unsigned long long)hctx->bytes_in_buffer); | ||
359 | + log_error_write(srv, __FILE__, __LINE__, "ss", | ||
360 | + "(debug) found using ctx,", msgbuf); | ||
361 | +#endif | ||
362 | + cgi_throttling_control(srv, hctx); | ||
363 | + } | ||
364 | + | ||
365 | /* the trigger handle only cares about lonely PID which we have to wait for */ | ||
366 | #ifndef __WIN32 | ||
367 | |||
368 | @@ -1330,7 +1498,8 @@ SUBREQUEST_FUNC(mod_cgi_handle_subrequest) { | ||
369 | log_error_write(srv, __FILE__, __LINE__, "sds", "cgi close failed ", hctx->fd, strerror(errno)); | ||
370 | } | ||
371 | |||
372 | - cgi_handler_ctx_free(hctx); | ||
373 | + cgi_ctx_del(p, hctx); | ||
374 | + cgi_handler_ctx_free(srv, hctx); | ||
375 | |||
376 | con->plugin_ctx[p->id] = NULL; | ||
377 | |||
378 | @@ -1362,7 +1531,8 @@ SUBREQUEST_FUNC(mod_cgi_handle_subrequest) { | ||
379 | log_error_write(srv, __FILE__, __LINE__, "sds", "cgi close failed ", hctx->fd, strerror(errno)); | ||
380 | } | ||
381 | |||
382 | - cgi_handler_ctx_free(hctx); | ||
383 | + cgi_ctx_del(p, hctx); | ||
384 | + cgi_handler_ctx_free(srv, hctx); | ||
385 | |||
386 | con->plugin_ctx[p->id] = NULL; | ||
387 | return HANDLER_FINISHED; | ||
diff --git a/meta/recipes-extended/lighttpd/lighttpd_1.4.39.bb b/meta/recipes-extended/lighttpd/lighttpd_1.4.39.bb index a407d030fb..378accbf11 100644 --- a/meta/recipes-extended/lighttpd/lighttpd_1.4.39.bb +++ b/meta/recipes-extended/lighttpd/lighttpd_1.4.39.bb | |||
@@ -21,7 +21,6 @@ SRC_URI = "http://download.lighttpd.net/lighttpd/releases-1.4.x/lighttpd-${PV}.t | |||
21 | file://lighttpd \ | 21 | file://lighttpd \ |
22 | file://lighttpd.service \ | 22 | file://lighttpd.service \ |
23 | file://pkgconfig.patch \ | 23 | file://pkgconfig.patch \ |
24 | file://0001-mod_cgi-buffers-data-without-bound.patch \ | ||
25 | " | 24 | " |
26 | 25 | ||
27 | SRC_URI[md5sum] = "63c7563be1c7a7a9819a51f07f1af8b2" | 26 | SRC_URI[md5sum] = "63c7563be1c7a7a9819a51f07f1af8b2" |