diff options
| author | Kang Kai <kai.kang@windriver.com> | 2014-10-29 09:40:08 +0800 |
|---|---|---|
| committer | Paul Eggleton <paul.eggleton@linux.intel.com> | 2014-10-31 11:35:25 +0000 |
| commit | a4fd0b34103f3fc6365eb154ea5277485ed01a5c (patch) | |
| tree | 8257c1c6f68300a33a9023f65d820a39ddfeeaed | |
| parent | 6aee5729848d48f57fdab9c6aafc61f86ad86135 (diff) | |
| download | meta-openembedded-a4fd0b34103f3fc6365eb154ea5277485ed01a5c.tar.gz | |
apache: add fix for CVE-2014-0117 Security Advisory
The patch comes from upstream:
http://svn.apache.org/viewvc?view=revision&revision=1610674
SECURITY (CVE-2014-0117): Fix a crash in mod_proxy. In a reverse proxy
configuration, a remote attacker could send a carefully crafted request which
could crash a server process, resulting in denial of service.
Thanks to Marek Kroemeke working with HP's Zero Day Initiative for reporting
this issue.
Submitted by: Edward Lu, breser, covener
Signed-off-by: Zhang Xiao <xiao.zhang@windriver.com>
Signed-off-by: Kai Kang <kai.kang@windriver.com>
| -rw-r--r-- | meta-webserver/recipes-httpd/apache2/apache2/apache-CVE-2014-0117.patch | 289 | ||||
| -rw-r--r-- | meta-webserver/recipes-httpd/apache2/apache2_2.4.10.bb | 4 |
2 files changed, 292 insertions, 1 deletions
diff --git a/meta-webserver/recipes-httpd/apache2/apache2/apache-CVE-2014-0117.patch b/meta-webserver/recipes-httpd/apache2/apache2/apache-CVE-2014-0117.patch new file mode 100644 index 0000000000..8585f0bb30 --- /dev/null +++ b/meta-webserver/recipes-httpd/apache2/apache2/apache-CVE-2014-0117.patch | |||
| @@ -0,0 +1,289 @@ | |||
| 1 | apache: CVE-2014-0117 | ||
| 2 | |||
| 3 | The patch comes from upstream: | ||
| 4 | http://svn.apache.org/viewvc?view=revision&revision=1610674 | ||
| 5 | |||
| 6 | SECURITY (CVE-2014-0117): Fix a crash in mod_proxy. In a | ||
| 7 | reverse proxy configuration, a remote attacker could send a carefully crafted | ||
| 8 | request which could crash a server process, resulting in denial of service. | ||
| 9 | |||
| 10 | Thanks to Marek Kroemeke working with HP's Zero Day Initiative for | ||
| 11 | reporting this issue. | ||
| 12 | |||
| 13 | Upstream-Status: Backport | ||
| 14 | |||
| 15 | Submitted by: Edward Lu, breser, covener | ||
| 16 | Signed-off-by: Zhang Xiao <xiao.zhang@windriver.com> | ||
| 17 | --- | ||
| 18 | modules/proxy/mod_proxy_http.c | 8 +++- | ||
| 19 | include/httpd.h | 17 ++++++++ | ||
| 20 | modules/proxy/proxy_util.c | 67 ++++++++++++++---------------- | ||
| 21 | server/util.c | 89 ++++++++++++++++++++++++++++++++++++++++++ | ||
| 22 | 4 files changed, 143 insertions(+), 38 deletions(-) | ||
| 23 | |||
| 24 | diff --git a/modules/proxy/mod_proxy_http.c b/modules/proxy/mod_proxy_http.c | ||
| 25 | index cffad2e..f11c16f 100644 | ||
| 26 | --- a/modules/proxy/mod_proxy_http.c | ||
| 27 | +++ b/modules/proxy/mod_proxy_http.c | ||
| 28 | @@ -1362,6 +1362,7 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r, | ||
| 29 | */ | ||
| 30 | if (apr_date_checkmask(buffer, "HTTP/#.# ###*")) { | ||
| 31 | int major, minor; | ||
| 32 | + int toclose; | ||
| 33 | |||
| 34 | major = buffer[5] - '0'; | ||
| 35 | minor = buffer[7] - '0'; | ||
| 36 | @@ -1470,7 +1471,12 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r, | ||
| 37 | te = apr_table_get(r->headers_out, "Transfer-Encoding"); | ||
| 38 | |||
| 39 | /* strip connection listed hop-by-hop headers from response */ | ||
| 40 | - backend->close = ap_proxy_clear_connection_fn(r, r->headers_out); | ||
| 41 | + toclose = ap_proxy_clear_connection_fn(r, r->headers_out); | ||
| 42 | + backend->close = (toclose != 0); | ||
| 43 | + if (toclose < 0) { | ||
| 44 | + return ap_proxyerror(r, HTTP_BAD_REQUEST, | ||
| 45 | + "Malformed connection header"); | ||
| 46 | + } | ||
| 47 | |||
| 48 | if ((buf = apr_table_get(r->headers_out, "Content-Type"))) { | ||
| 49 | ap_set_content_type(r, apr_pstrdup(p, buf)); | ||
| 50 | diff --git a/include/httpd.h b/include/httpd.h | ||
| 51 | index 36cd58d..9a2cf5c 100644 | ||
| 52 | --- a/include/httpd.h | ||
| 53 | +++ b/include/httpd.h | ||
| 54 | @@ -1528,6 +1528,23 @@ AP_DECLARE(int) ap_find_etag_weak(apr_pool_t *p, const char *line, const char *t | ||
| 55 | AP_DECLARE(int) ap_find_etag_strong(apr_pool_t *p, const char *line, const char *tok); | ||
| 56 | |||
| 57 | /** | ||
| 58 | + * Retrieve an array of tokens in the format "1#token" defined in RFC2616. Only | ||
| 59 | + * accepts ',' as a delimiter, does not accept quoted strings, and errors on | ||
| 60 | + * any separator. | ||
| 61 | + * @param p The pool to allocate from | ||
| 62 | + * @param tok The line to read tokens from | ||
| 63 | + * @param tokens Pointer to an array of tokens. If not NULL, must be an array | ||
| 64 | + * of char*, otherwise it will be allocated on @a p when a token is found | ||
| 65 | + * @param skip_invalid If true, when an invalid separator is encountered, it | ||
| 66 | + * will be ignored. | ||
| 67 | + * @return NULL on success, an error string otherwise. | ||
| 68 | + * @remark *tokens may be NULL on output if NULL in input and no token is found | ||
| 69 | + */ | ||
| 70 | +AP_DECLARE(const char *) ap_parse_token_list_strict(apr_pool_t *p, const char *tok, | ||
| 71 | + apr_array_header_t **tokens, | ||
| 72 | + int skip_invalid); | ||
| 73 | + | ||
| 74 | +/** | ||
| 75 | * Retrieve a token, spacing over it and adjusting the pointer to | ||
| 76 | * the first non-white byte afterwards. Note that these tokens | ||
| 77 | * are delimited by semis and commas and can also be delimited | ||
| 78 | diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c | ||
| 79 | index 67dc939..58daa21 100644 | ||
| 80 | --- a/modules/proxy/proxy_util.c | ||
| 81 | +++ b/modules/proxy/proxy_util.c | ||
| 82 | @@ -2847,68 +2847,59 @@ PROXY_DECLARE(proxy_balancer_shared *) ap_proxy_find_balancershm(ap_slotmem_prov | ||
| 83 | typedef struct header_connection { | ||
| 84 | apr_pool_t *pool; | ||
| 85 | apr_array_header_t *array; | ||
| 86 | - const char *first; | ||
| 87 | - unsigned int closed:1; | ||
| 88 | + const char *error; | ||
| 89 | + int is_req; | ||
| 90 | } header_connection; | ||
| 91 | |||
| 92 | static int find_conn_headers(void *data, const char *key, const char *val) | ||
| 93 | { | ||
| 94 | header_connection *x = data; | ||
| 95 | - const char *name; | ||
| 96 | - | ||
| 97 | - do { | ||
| 98 | - while (*val == ',' || *val == ';') { | ||
| 99 | - val++; | ||
| 100 | - } | ||
| 101 | - name = ap_get_token(x->pool, &val, 0); | ||
| 102 | - if (!strcasecmp(name, "close")) { | ||
| 103 | - x->closed = 1; | ||
| 104 | - } | ||
| 105 | - if (!x->first) { | ||
| 106 | - x->first = name; | ||
| 107 | - } | ||
| 108 | - else { | ||
| 109 | - const char **elt; | ||
| 110 | - if (!x->array) { | ||
| 111 | - x->array = apr_array_make(x->pool, 4, sizeof(char *)); | ||
| 112 | - } | ||
| 113 | - elt = apr_array_push(x->array); | ||
| 114 | - *elt = name; | ||
| 115 | - } | ||
| 116 | - } while (*val); | ||
| 117 | |||
| 118 | - return 1; | ||
| 119 | + x->error = ap_parse_token_list_strict(x->pool, val, &x->array, !x->is_req); | ||
| 120 | + return !x->error; | ||
| 121 | } | ||
| 122 | |||
| 123 | /** | ||
| 124 | * Remove all headers referred to by the Connection header. | ||
| 125 | + * Returns -1 on error. Otherwise, returns 1 if 'Close' was seen in | ||
| 126 | + * the Connection header tokens, and 0 if not. | ||
| 127 | */ | ||
| 128 | static int ap_proxy_clear_connection(request_rec *r, apr_table_t *headers) | ||
| 129 | { | ||
| 130 | - const char **name; | ||
| 131 | + int closed = 0; | ||
| 132 | header_connection x; | ||
| 133 | |||
| 134 | x.pool = r->pool; | ||
| 135 | x.array = NULL; | ||
| 136 | - x.first = NULL; | ||
| 137 | - x.closed = 0; | ||
| 138 | + x.error = NULL; | ||
| 139 | + x.is_req = (headers == r->headers_in); | ||
| 140 | |||
| 141 | apr_table_unset(headers, "Proxy-Connection"); | ||
| 142 | |||
| 143 | apr_table_do(find_conn_headers, &x, headers, "Connection", NULL); | ||
| 144 | - if (x.first) { | ||
| 145 | - /* fast path - no memory allocated for one header */ | ||
| 146 | - apr_table_unset(headers, "Connection"); | ||
| 147 | - apr_table_unset(headers, x.first); | ||
| 148 | + apr_table_unset(headers, "Connection"); | ||
| 149 | + | ||
| 150 | + if (x.error) { | ||
| 151 | + ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r, APLOGNO() | ||
| 152 | + "Error parsing Connection header: %s", x.error); | ||
| 153 | + return -1; | ||
| 154 | } | ||
| 155 | + | ||
| 156 | if (x.array) { | ||
| 157 | - /* two or more headers */ | ||
| 158 | - while ((name = apr_array_pop(x.array))) { | ||
| 159 | - apr_table_unset(headers, *name); | ||
| 160 | + int i; | ||
| 161 | + for (i = 0; i < x.array->nelts; i++) { | ||
| 162 | + const char *name = APR_ARRAY_IDX(x.array, i, const char *); | ||
| 163 | + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO() | ||
| 164 | + "Removing header '%s' listed in Connection header", | ||
| 165 | + name); | ||
| 166 | + if (!strcasecmp(name, "close")) { | ||
| 167 | + closed = 1; | ||
| 168 | + } | ||
| 169 | + apr_table_unset(headers, name); | ||
| 170 | } | ||
| 171 | } | ||
| 172 | |||
| 173 | - return x.closed; | ||
| 174 | + return closed; | ||
| 175 | } | ||
| 176 | |||
| 177 | PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p, | ||
| 178 | @@ -3095,7 +3086,9 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p, | ||
| 179 | * apr is compiled with APR_POOL_DEBUG. | ||
| 180 | */ | ||
| 181 | headers_in_copy = apr_table_copy(r->pool, r->headers_in); | ||
| 182 | - ap_proxy_clear_connection(r, headers_in_copy); | ||
| 183 | + if (ap_proxy_clear_connection(r, headers_in_copy) < 0) { | ||
| 184 | + return HTTP_BAD_REQUEST; | ||
| 185 | + } | ||
| 186 | /* send request headers */ | ||
| 187 | headers_in_array = apr_table_elts(headers_in_copy); | ||
| 188 | headers_in = (const apr_table_entry_t *) headers_in_array->elts; | ||
| 189 | diff --git a/server/util.c b/server/util.c | ||
| 190 | index e0ba5c2..541c9f0 100644 | ||
| 191 | --- a/server/util.c | ||
| 192 | +++ b/server/util.c | ||
| 193 | @@ -1449,6 +1449,95 @@ AP_DECLARE(int) ap_find_etag_weak(apr_pool_t *p, const char *line, | ||
| 194 | return find_list_item(p, line, tok, AP_ETAG_WEAK); | ||
| 195 | } | ||
| 196 | |||
| 197 | +/* Grab a list of tokens of the format 1#token (from RFC7230) */ | ||
| 198 | +AP_DECLARE(const char *) ap_parse_token_list_strict(apr_pool_t *p, | ||
| 199 | + const char *str_in, | ||
| 200 | + apr_array_header_t **tokens, | ||
| 201 | + int skip_invalid) | ||
| 202 | +{ | ||
| 203 | + int in_leading_space = 1; | ||
| 204 | + int in_trailing_space = 0; | ||
| 205 | + int string_end = 0; | ||
| 206 | + const char *tok_begin; | ||
| 207 | + const char *cur; | ||
| 208 | + | ||
| 209 | + if (!str_in) { | ||
| 210 | + return NULL; | ||
| 211 | + } | ||
| 212 | + | ||
| 213 | + tok_begin = cur = str_in; | ||
| 214 | + | ||
| 215 | + while (!string_end) { | ||
| 216 | + const unsigned char c = (unsigned char)*cur; | ||
| 217 | + | ||
| 218 | + if (!TEST_CHAR(c, T_HTTP_TOKEN_STOP) && c != '\0') { | ||
| 219 | + /* Non-separator character; we are finished with leading | ||
| 220 | + * whitespace. We must never have encountered any trailing | ||
| 221 | + * whitespace before the delimiter (comma) */ | ||
| 222 | + in_leading_space = 0; | ||
| 223 | + if (in_trailing_space) { | ||
| 224 | + return "Encountered illegal whitespace in token"; | ||
| 225 | + } | ||
| 226 | + } | ||
| 227 | + else if (c == ' ' || c == '\t') { | ||
| 228 | + /* "Linear whitespace" only includes ASCII CRLF, space, and tab; | ||
| 229 | + * we can't get a CRLF since headers are split on them already, | ||
| 230 | + * so only look for a space or a tab */ | ||
| 231 | + if (in_leading_space) { | ||
| 232 | + /* We're still in leading whitespace */ | ||
| 233 | + ++tok_begin; | ||
| 234 | + } | ||
| 235 | + else { | ||
| 236 | + /* We must be in trailing whitespace */ | ||
| 237 | + ++in_trailing_space; | ||
| 238 | + } | ||
| 239 | + } | ||
| 240 | + else if (c == ',' || c == '\0') { | ||
| 241 | + if (!in_leading_space) { | ||
| 242 | + /* If we're out of the leading space, we know we've read some | ||
| 243 | + * characters of a token */ | ||
| 244 | + if (*tokens == NULL) { | ||
| 245 | + *tokens = apr_array_make(p, 4, sizeof(char *)); | ||
| 246 | + } | ||
| 247 | + APR_ARRAY_PUSH(*tokens, char *) = | ||
| 248 | + apr_pstrmemdup((*tokens)->pool, tok_begin, | ||
| 249 | + (cur - tok_begin) - in_trailing_space); | ||
| 250 | + } | ||
| 251 | + /* We're allowed to have null elements, just don't add them to the | ||
| 252 | + * array */ | ||
| 253 | + | ||
| 254 | + tok_begin = cur + 1; | ||
| 255 | + in_leading_space = 1; | ||
| 256 | + in_trailing_space = 0; | ||
| 257 | + string_end = (c == '\0'); | ||
| 258 | + } | ||
| 259 | + else { | ||
| 260 | + /* Encountered illegal separator char */ | ||
| 261 | + if (skip_invalid) { | ||
| 262 | + /* Skip to the next separator */ | ||
| 263 | + const char *temp; | ||
| 264 | + temp = ap_strchr_c(cur, ','); | ||
| 265 | + if(!temp) { | ||
| 266 | + temp = ap_strchr_c(cur, '\0'); | ||
| 267 | + } | ||
| 268 | + | ||
| 269 | + /* Act like we haven't seen a token so we reset */ | ||
| 270 | + cur = temp - 1; | ||
| 271 | + in_leading_space = 1; | ||
| 272 | + in_trailing_space = 0; | ||
| 273 | + } | ||
| 274 | + else { | ||
| 275 | + return apr_psprintf(p, "Encountered illegal separator " | ||
| 276 | + "'\\x%.2x'", (unsigned int)c); | ||
| 277 | + } | ||
| 278 | + } | ||
| 279 | + | ||
| 280 | + ++cur; | ||
| 281 | + } | ||
| 282 | + | ||
| 283 | + return NULL; | ||
| 284 | +} | ||
| 285 | + | ||
| 286 | /* Retrieve a token, spacing over it and returning a pointer to | ||
| 287 | * the first non-white byte afterwards. Note that these tokens | ||
| 288 | * are delimited by semis and commas; and can also be delimited | ||
| 289 | -- | ||
diff --git a/meta-webserver/recipes-httpd/apache2/apache2_2.4.10.bb b/meta-webserver/recipes-httpd/apache2/apache2_2.4.10.bb index 573cd6fb00..d79d40bd2c 100644 --- a/meta-webserver/recipes-httpd/apache2/apache2_2.4.10.bb +++ b/meta-webserver/recipes-httpd/apache2/apache2_2.4.10.bb | |||
| @@ -19,7 +19,9 @@ SRC_URI = "http://www.apache.org/dist/httpd/httpd-${PV}.tar.bz2 \ | |||
| 19 | file://0001-configure-use-pkg-config-for-PCRE-detection.patch \ | 19 | file://0001-configure-use-pkg-config-for-PCRE-detection.patch \ |
| 20 | file://init \ | 20 | file://init \ |
| 21 | file://apache2-volatile.conf \ | 21 | file://apache2-volatile.conf \ |
| 22 | file://apache2.service" | 22 | file://apache2.service \ |
| 23 | file://apache-CVE-2014-0117.patch \ | ||
| 24 | " | ||
| 23 | 25 | ||
| 24 | LIC_FILES_CHKSUM = "file://LICENSE;md5=dbff5a2b542fa58854455bf1a0b94b83" | 26 | LIC_FILES_CHKSUM = "file://LICENSE;md5=dbff5a2b542fa58854455bf1a0b94b83" |
| 25 | SRC_URI[md5sum] = "44543dff14a4ebc1e9e2d86780507156" | 27 | SRC_URI[md5sum] = "44543dff14a4ebc1e9e2d86780507156" |
