<div dir="ltr">The short log should be more expressive than "bug fix", and is Pending the correct upstream status?<div><br></div><div>Ross</div></div><div class="gmail_extra"><br><div class="gmail_quote">On 17 June 2015 at 02:34, Li xin <span dir="ltr"><<a href="mailto:lixin.fnst@cn.fujitsu.com" target="_blank">lixin.fnst@cn.fujitsu.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">mod_cgi buffers data without bound,so fix it.<br>
<br>
Reference: <a href="http://redmine.lighttpd.net/issues/1264" rel="noreferrer" target="_blank">http://redmine.lighttpd.net/issues/1264</a><br>
<br>
Signed-off-by: Li Xin <<a href="mailto:lixin.fnst@cn.fujitsu.com">lixin.fnst@cn.fujitsu.com</a>><br>
---<br>
.../0001-mod_cgi-buffers-data-without-bound.patch | 386 +++++++++++++++++++++<br>
meta/recipes-extended/lighttpd/<a href="http://lighttpd_1.4.35.bb" rel="noreferrer" target="_blank">lighttpd_1.4.35.bb</a> | 1 +<br>
2 files changed, 387 insertions(+)<br>
create mode 100644 meta/recipes-extended/lighttpd/lighttpd/0001-mod_cgi-buffers-data-without-bound.patch<br>
<br>
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<br>
new file mode 100644<br>
index 0000000..e456182<br>
--- /dev/null<br>
+++ b/meta/recipes-extended/lighttpd/lighttpd/0001-mod_cgi-buffers-data-without-bound.patch<br>
@@ -0,0 +1,386 @@<br>
+From e6ccbab5d42b110ac4f6ce1f72cb1e9ccbe4400a Mon Sep 17 00:00:00 2001<br>
+From: Li xin <<a href="mailto:lixin.fnst@cn.fujitsu.com">lixin.fnst@cn.fujitsu.com</a>><br>
+Date: Tue, 16 Jun 2015 19:02:38 +0900<br>
+Subject: [PATCH] mod_cgi buffers data without bound so fix it<br>
+<br>
+Upstream-Status: pending<br>
+<br>
+Signed-off-by: Li Xin <<a href="mailto:lixin.fnst@cn.fujitsu.com">lixin.fnst@cn.fujitsu.com</a>><br>
+---<br>
+ doc/config/lighttpd.conf | 8 ++<br>
+ src/mod_cgi.c | 188 ++++++++++++++++++++++++++++++++++++++++++++---<br>
+ 2 files changed, 186 insertions(+), 10 deletions(-)<br>
+<br>
+diff --git a/doc/config/lighttpd.conf b/doc/config/lighttpd.conf<br>
+index 60b0ae1..9c101a7 100644<br>
+--- a/doc/config/lighttpd.conf<br>
++++ b/doc/config/lighttpd.conf<br>
+@@ -375,6 +375,14 @@ server.upload-dirs = ( "/var/tmp" )<br>
+ ##<br>
+ #######################################################################<br>
+<br>
++#######################################################################<br>
++##<br>
++##<br>
++## maximum bytes in send_raw before backing off [KByte]<br>
++## cgi.high-waterlevel = 10240<br>
++## minimum bytes in send_raw to disable backoff [KByte]<br>
++## cgi.low-waterlevel = 5120<br>
++#######################################################################<br>
+<br>
+ #######################################################################<br>
+ ##<br>
+diff --git a/src/mod_cgi.c b/src/mod_cgi.c<br>
+index 734ecee..c51f43c 100644<br>
+--- a/src/mod_cgi.c<br>
++++ b/src/mod_cgi.c<br>
+@@ -38,6 +38,10 @@<br>
+<br>
+ #include "version.h"<br>
+<br>
++/* for output logs */<br>
++char msgbuf[2048];<br>
++<br>
++<br>
+ enum {EOL_UNSET, EOL_N, EOL_RN};<br>
+<br>
+ typedef struct {<br>
+@@ -53,9 +57,19 @@ typedef struct {<br>
+ size_t size;<br>
+ } buffer_pid_t;<br>
+<br>
++struct handler_ctx;<br>
++<br>
++typedef struct {<br>
++ struct handler_ctx **hctx;<br>
++ size_t used;<br>
++ size_t size;<br>
++} buffer_ctx_t;<br>
++<br>
+ typedef struct {<br>
+ array *cgi;<br>
+ unsigned short execute_x_only;<br>
++ unsigned int high_waterlevel; /* maximum bytes in send_raw before backing off */<br>
++ unsigned int low_waterlevel; /* minimum bytes in send_raw to disable backoff */<br>
+ } plugin_config;<br>
+<br>
+ typedef struct {<br>
+@@ -68,9 +82,11 @@ typedef struct {<br>
+ plugin_config **config_storage;<br>
+<br>
+ plugin_config conf;<br>
++<br>
++ buffer_ctx_t cgi_ctx;<br>
+ } plugin_data;<br>
+<br>
+-typedef struct {<br>
++typedef struct handler_ctx {<br>
+ pid_t pid;<br>
+ int fd;<br>
+ int fde_ndx; /* index into the fd-event buffer */<br>
+@@ -78,11 +94,16 @@ typedef struct {<br>
+ connection *remote_conn; /* dumb pointer */<br>
+ plugin_data *plugin_data; /* dumb pointer */<br>
+<br>
++ int throttling; /* 1=waiting for send_raw buffer to drain */<br>
++ off_t high_waterlevel; /* maximum bytes in send_raw before backing off */<br>
++ off_t low_waterlevel; /* minimum bytes in send_raw to disable backoff */<br>
++ off_t bytes_in_buffer;<br>
++<br>
+ buffer *response;<br>
+ buffer *response_header;<br>
+ } handler_ctx;<br>
+<br>
+-static handler_ctx * cgi_handler_ctx_init(void) {<br>
++static handler_ctx * cgi_handler_ctx_init(plugin_data *p) {<br>
+ handler_ctx *hctx = calloc(1, sizeof(*hctx));<br>
+<br>
+ force_assert(hctx);<br>
+@@ -90,13 +111,26 @@ static handler_ctx * cgi_handler_ctx_init(void) {<br>
+ hctx->response = buffer_init();<br>
+ hctx->response_header = buffer_init();<br>
+<br>
++ hctx->throttling = 0;<br>
++ hctx->high_waterlevel = (off_t)p->conf.high_waterlevel * 1024;<br>
++ hctx->low_waterlevel = (off_t)p->conf.low_waterlevel * 1024;<br>
++ if (hctx->low_waterlevel >= hctx->high_waterlevel) {<br>
++ hctx->low_waterlevel = hctx->high_waterlevel * 3 / 4; /* 75% */<br>
++ }<br>
++ hctx->bytes_in_buffer = 0;<br>
++<br>
+ return hctx;<br>
+ }<br>
+<br>
+-static void cgi_handler_ctx_free(handler_ctx *hctx) {<br>
++static void cgi_handler_ctx_free(server *srv, handler_ctx *hctx) {<br>
+ buffer_free(hctx->response);<br>
+ buffer_free(hctx->response_header);<br>
+<br>
++ /* to avoid confusion */<br>
++ if (hctx->throttling) {<br>
++ log_error_write(srv, __FILE__, __LINE__, "s", "unthrottled");<br>
++ }<br>
++<br>
+ free(hctx);<br>
+ }<br>
+<br>
+@@ -152,6 +186,8 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {<br>
+ config_values_t cv[] = {<br>
+ { "cgi.assign", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */<br>
+ { "cgi.execute-x-only", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 1 */<br>
++ { "cgi.high-waterlevel", NULL, T_CONFIG_INT, T_CONFIG_SCOPE_CONNECTION }, /* 2 */<br>
++ { "cgi.low-waterlevel", NULL, T_CONFIG_INT, T_CONFIG_SCOPE_CONNECTION }, /* 3 */<br>
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET}<br>
+ };<br>
+<br>
+@@ -167,9 +203,13 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {<br>
+<br>
+ s->cgi = array_init();<br>
+ s->execute_x_only = 0;<br>
++ s->high_waterlevel = 0; /* 0 == disabled */<br>
++ s->low_waterlevel = 0;<br>
+<br>
+ cv[0].destination = s->cgi;<br>
+ cv[1].destination = &(s->execute_x_only);<br>
++ cv[2].destination = &(s->high_waterlevel);<br>
++ cv[3].destination = &(s->low_waterlevel);<br>
+<br>
+ p->config_storage[i] = s;<br>
+<br>
+@@ -182,6 +222,51 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {<br>
+ }<br>
+<br>
+<br>
++static void cgi_recount_bytes_in_buffer(handler_ctx *hctx)<br>
++{<br>
++ chunkqueue *cq = hctx->remote_conn->write_queue;<br>
++ hctx->bytes_in_buffer = chunkqueue_length(cq) - chunkqueue_written(cq);<br>
++}<br>
++<br>
++<br>
++static void cgi_throttling_control(server *srv, handler_ctx *hctx)<br>
++{<br>
++ cgi_recount_bytes_in_buffer(hctx);<br>
++<br>
++#ifdef DEBUG<br>
++ sprintf(msgbuf, "throttling=%d, chars=%llu, high=%llu, low=%llu",<br>
++ hctx->throttling, hctx->bytes_in_buffer,<br>
++ hctx->high_waterlevel, hctx->low_waterlevel);<br>
++ log_error_write(srv, __FILE__, __LINE__, "ss",<br>
++ "(debug) throttling control,", msgbuf);<br>
++#endif<br>
++<br>
++ if (hctx->throttling) {<br>
++ sprintf(msgbuf, "throttling; chars in queue=%llu,"<br>
++ " low-waterlevel=%llu, high-waterlevel=%llu",<br>
++ hctx->bytes_in_buffer,<br>
++ hctx->low_waterlevel, hctx->high_waterlevel);<br>
++ log_error_write(srv, __FILE__, __LINE__, "s", msgbuf);<br>
++ if (hctx->bytes_in_buffer <= hctx->low_waterlevel) {<br>
++ fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);<br>
++ hctx->throttling = 0;<br>
++ log_error_write(srv, __FILE__, __LINE__, "s", "unthrottled");<br>
++ }<br>
++ } else {<br>
++ if (hctx->high_waterlevel != 0 &&<br>
++ hctx->high_waterlevel <= hctx->bytes_in_buffer) {<br>
++ fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);<br>
++ hctx->throttling = 1;<br>
++ sprintf(msgbuf, "throttled; chars in queue=%llu,"<br>
++ " low-waterlevel=%llu, high-waterlevel=%llu",<br>
++ hctx->bytes_in_buffer,<br>
++ hctx->low_waterlevel, hctx->high_waterlevel);<br>
++ log_error_write(srv, __FILE__, __LINE__, "s", msgbuf);<br>
++ }<br>
++ }<br>
++}<br>
++<br>
++<br>
+ static int cgi_pid_add(server *srv, plugin_data *p, pid_t pid) {<br>
+ int m = -1;<br>
+ size_t i;<br>
+@@ -228,6 +313,39 @@ static int cgi_pid_del(server *srv, plugin_data *p, pid_t pid) {<br>
+ return 0;<br>
+ }<br>
+<br>
++<br>
++static void cgi_ctx_add(plugin_data *p, handler_ctx *hctx) {<br>
++ buffer_ctx_t *r = &(p->cgi_ctx);<br>
++<br>
++ if (r->size == 0) {<br>
++ r->size = 16;<br>
++ r->hctx = malloc(sizeof(*r->hctx) * r->size);<br>
++ } else if (r->used == r->size) {<br>
++ r->size += 16;<br>
++ r->hctx = realloc(r->hctx, sizeof(*r->hctx) * r->size);<br>
++ }<br>
++<br>
++ r->hctx[r->used++] = hctx;<br>
++}<br>
++<br>
++static void cgi_ctx_del(plugin_data *p, handler_ctx *hctx) {<br>
++ size_t i;<br>
++ buffer_ctx_t *r = &(p->cgi_ctx);<br>
++<br>
++ for (i = 0; i < r->used; i++) {<br>
++ if (r->hctx[i] == hctx) break;<br>
++ }<br>
++<br>
++ if (i != r->used) {<br>
++ /* found */<br>
++<br>
++ if (i != r->used - 1) {<br>
++ r->hctx[i] = r->hctx[r->used - 1];<br>
++ }<br>
++ r->used--;<br>
++ }<br>
++}<br>
++<br>
+ static int cgi_response_parse(server *srv, connection *con, plugin_data *p, buffer *in) {<br>
+ char *ns;<br>
+ const char *s;<br>
+@@ -378,6 +496,13 @@ static int cgi_demux_response(server *srv, handler_ctx *hctx) {<br>
+<br>
+ hctx->response->ptr[n] = '\0';<br>
+ hctx->response->used = n+1;<br>
++#ifdef DEBUG<br>
++ sprintf(msgbuf, "n=%d, bytes_out=%llu, bytes_in=%llu", n,<br>
++ (unsigned long long)con->write_queue->bytes_out,<br>
++ (unsigned long long)con->write_queue->bytes_in);<br>
++ log_error_write(srv, __FILE__, __LINE__, "ss",<br>
++ "(debug) read,", msgbuf);<br>
++#endif<br>
+<br>
+ /* split header from body */<br>
+<br>
+@@ -502,8 +627,20 @@ static int cgi_demux_response(server *srv, handler_ctx *hctx) {<br>
+ }<br>
+ } else {<br>
+ http_chunk_append_mem(srv, con, hctx->response->ptr, hctx->response->used);<br>
++#ifdef DEBUG<br>
++ sprintf(msgbuf, "n=%d, bytes_out=%llu, bytes_in=%llu, limit=%llu", n,<br>
++ (unsigned long long)con->write_queue->bytes_out,<br>
++ (unsigned long long)con->write_queue->bytes_in,<br>
++ (unsigned long long)hctx->high_waterlevel);<br>
++ log_error_write(srv, __FILE__, __LINE__,<br>
++ "ss", "(debug) append,", msgbuf);<br>
++#endif<br>
+ joblist_append(srv, con);<br>
+- }<br>
++ cgi_throttling_control(srv, hctx);<br>
++ if (hctx->throttling) {<br>
++ return FDEVENT_HANDLED_NOT_FINISHED;<br>
++ }<br>
++ }<br>
+<br>
+ #if 0<br>
+ log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), b->ptr);<br>
+@@ -552,8 +689,9 @@ static handler_t cgi_connection_close(server *srv, handler_ctx *hctx) {<br>
+ con->plugin_ctx[p->id] = NULL;<br>
+<br>
+ /* is this a good idea ? */<br>
+- cgi_handler_ctx_free(hctx);<br>
+-<br>
++ cgi_ctx_del(p, hctx);<br>
++ cgi_handler_ctx_free(srv, hctx);<br>
++<br>
+ /* if waitpid hasn't been called by response.c yet, do it here */<br>
+ if (pid) {<br>
+ /* check if the CGI-script is already gone */<br>
+@@ -1156,7 +1294,8 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer *<br>
+ con->mode = p->id;<br>
+ buffer_reset(con->physical.path);<br>
+<br>
+- hctx = cgi_handler_ctx_init();<br>
++ hctx = cgi_handler_ctx_init(p);<br>
++ cgi_ctx_add(p, hctx);<br>
+<br>
+ hctx->remote_conn = con;<br>
+ hctx->plugin_data = p;<br>
+@@ -1165,6 +1304,11 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer *<br>
+ hctx->fde_ndx = -1;<br>
+<br>
+ con->plugin_ctx[p->id] = hctx;<br>
++#ifdef DEBUG<br>
++ sprintf(msgbuf, "hctx=%p, con=%p", (void*)hctx, (void*)con);<br>
++ log_error_write(srv, __FILE__, __LINE__, "ss",<br>
++ "(debug) hctx generated, ", msgbuf);<br>
++#endif<br>
+<br>
+ fdevent_register(srv->ev, hctx->fd, cgi_handle_fdevent, hctx);<br>
+ fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);<br>
+@@ -1179,7 +1323,8 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer *<br>
+<br>
+ close(hctx->fd);<br>
+<br>
+- cgi_handler_ctx_free(hctx);<br>
++ cgi_ctx_del(p, hctx);<br>
++ cgi_handler_ctx_free(srv, hctx);<br>
+<br>
+ con->plugin_ctx[p->id] = NULL;<br>
+<br>
+@@ -1204,6 +1349,8 @@ static int mod_cgi_patch_connection(server *srv, connection *con, plugin_data *p<br>
+<br>
+ PATCH(cgi);<br>
+ PATCH(execute_x_only);<br>
++ PATCH(high_waterlevel);<br>
++ PATCH(low_waterlevel);<br>
+<br>
+ /* skip the first, the global context */<br>
+ for (i = 1; i < srv->config_context->used; i++) {<br>
+@@ -1221,6 +1368,10 @@ static int mod_cgi_patch_connection(server *srv, connection *con, plugin_data *p<br>
+ PATCH(cgi);<br>
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cgi.execute-x-only"))) {<br>
+ PATCH(execute_x_only);<br>
++ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cgi.high-waterlevel"))) {<br>
++ PATCH(high_waterlevel);<br>
++ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cgi.low-waterlevel"))) {<br>
++ PATCH(low_waterlevel);<br>
+ }<br>
+ }<br>
+ }<br>
+@@ -1273,6 +1424,21 @@ URIHANDLER_FUNC(cgi_is_handled) {<br>
+ TRIGGER_FUNC(cgi_trigger) {<br>
+ plugin_data *p = p_d;<br>
+ size_t ndx;<br>
++<br>
++ for (ndx = 0; ndx < p->cgi_ctx.used; ndx++) {<br>
++ handler_ctx *hctx = p->cgi_ctx.hctx[ndx];<br>
++#ifdef DEBUG<br>
++ connection *con = hctx->remote_conn;<br>
++<br>
++ sprintf(msgbuf, "hctx=%p, con=%p, bytes_in_buffer=%llu",<br>
++ (void*)hctx, (void*)con,<br>
++ (unsigned long long)hctx->bytes_in_buffer);<br>
++ log_error_write(srv, __FILE__, __LINE__, "ss",<br>
++ "(debug) found using ctx,", msgbuf);<br>
++#endif<br>
++ cgi_throttling_control(srv, hctx);<br>
++ }<br>
++<br>
+ /* the trigger handle only cares about lonely PID which we have to wait for */<br>
+ #ifndef __WIN32<br>
+<br>
+@@ -1381,7 +1547,8 @@ SUBREQUEST_FUNC(mod_cgi_handle_subrequest) {<br>
+ log_error_write(srv, __FILE__, __LINE__, "sds", "cgi close failed ", hctx->fd, strerror(errno));<br>
+ }<br>
+<br>
+- cgi_handler_ctx_free(hctx);<br>
++ cgi_ctx_del(p, hctx);<br>
++ cgi_handler_ctx_free(srv, hctx);<br>
+<br>
+ con->plugin_ctx[p->id] = NULL;<br>
+<br>
+@@ -1413,7 +1580,8 @@ SUBREQUEST_FUNC(mod_cgi_handle_subrequest) {<br>
+ log_error_write(srv, __FILE__, __LINE__, "sds", "cgi close failed ", hctx->fd, strerror(errno));<br>
+ }<br>
+<br>
+- cgi_handler_ctx_free(hctx);<br>
++ cgi_ctx_del(p, hctx);<br>
++ cgi_handler_ctx_free(srv, hctx);<br>
+<br>
+ con->plugin_ctx[p->id] = NULL;<br>
+ return HANDLER_FINISHED;<br>
+--<br>
+1.8.4.2<br>
+<br>
diff --git a/meta/recipes-extended/lighttpd/<a href="http://lighttpd_1.4.35.bb" rel="noreferrer" target="_blank">lighttpd_1.4.35.bb</a> b/meta/recipes-extended/lighttpd/<a href="http://lighttpd_1.4.35.bb" rel="noreferrer" target="_blank">lighttpd_1.4.35.bb</a><br>
index 0cf5aa2..d3888e6 100644<br>
--- a/meta/recipes-extended/lighttpd/<a href="http://lighttpd_1.4.35.bb" rel="noreferrer" target="_blank">lighttpd_1.4.35.bb</a><br>
+++ b/meta/recipes-extended/lighttpd/<a href="http://lighttpd_1.4.35.bb" rel="noreferrer" target="_blank">lighttpd_1.4.35.bb</a><br>
@@ -24,6 +24,7 @@ SRC_URI = "<a href="http://download.lighttpd.net/lighttpd/releases-1.4.x/lighttpd-${PV}.t" rel="noreferrer" target="_blank">http://download.lighttpd.net/lighttpd/releases-1.4.x/lighttpd-${PV}.t</a><br>
file://lighttpd \<br>
file://lighttpd.service \<br>
file://pkgconfig.patch \<br>
+ file://0001-mod_cgi-buffers-data-without-bound.patch \<br>
"<br>
<br>
SRC_URI[md5sum] = "f7a88130ee9984b421ad8aa80629750a"<br>
<span class="HOEnZb"><font color="#888888">--<br>
1.8.4.2<br>
<br>
--<br>
_______________________________________________<br>
Openembedded-core mailing list<br>
<a href="mailto:Openembedded-core@lists.openembedded.org">Openembedded-core@lists.openembedded.org</a><br>
<a href="http://lists.openembedded.org/mailman/listinfo/openembedded-core" rel="noreferrer" target="_blank">http://lists.openembedded.org/mailman/listinfo/openembedded-core</a><br>
</font></span></blockquote></div><br></div>