Date: Friday, June 10, 2016 @ 08:23:08 Author: demize Revision: 179093
Patch CVE-2016-5360 http://www.openwall.com/lists/oss-security/2016/06/09/5 Added: haproxy/trunk/CVE-2016-5360-reqdeny.patch Modified: haproxy/trunk/PKGBUILD -----------------------------+ CVE-2016-5360-reqdeny.patch | 117 ++++++++++++++++++++++++++++++++++++++++++ PKGBUILD | 9 ++- 2 files changed, 123 insertions(+), 3 deletions(-) Added: CVE-2016-5360-reqdeny.patch =================================================================== --- CVE-2016-5360-reqdeny.patch (rev 0) +++ CVE-2016-5360-reqdeny.patch 2016-06-10 06:23:08 UTC (rev 179093) @@ -0,0 +1,117 @@ +From: Willy Tarreau <w...@1wt.eu> +Date: Wed, 25 May 2016 14:23:59 +0000 (+0200) +Subject: BUG/MAJOR: http: fix breakage of "reqdeny" causing random crashes +X-Git-Url: http://git.haproxy.org/?p=haproxy-1.6.git;a=commitdiff_plain;h=60f01f8c89e4fb2723d5a9f2046286e699567e0b;hp=0c60f3790d6f177f123d4ae63d5f17868c789d12 + +BUG/MAJOR: http: fix breakage of "reqdeny" causing random crashes + +Commit 108b1dd ("MEDIUM: http: configurable http result codes for +http-request deny") introduced in 1.6-dev2 was incomplete. It introduced +a new field "rule_deny_status" into struct http_txn, which is filled only +by actions "http-request deny" and "http-request tarpit". It's then used +in the deny code path to emit the proper error message, but is used +uninitialized when the deny comes from a "reqdeny" rule, causing random +behaviours ranging from returning a 200, an empty response, or crashing +the process. Often upon startup only 200 was returned but after the fields +are used the crash happens. This can be sped up using -dM. + +There's no need at all for storing this status in the http_txn struct +anyway since it's used immediately after being set. Let's store it in +a temporary variable instead which is passed as an argument to function +http_req_get_intercept_rule(). + +As an extra benefit, removing it from struct http_txn reduced the size +of this struct by 8 bytes. + +This fix must be backported to 1.6 where the bug was detected. Special +thanks to Falco Schmutz for his detailed report including an exploitable +core and a reproducer. +(cherry picked from commit 58727ec088e55f739b146cff3baa955f8d1b2a3e) +--- + +diff --git a/include/types/proto_http.h b/include/types/proto_http.h +index e5e9667..c3a73ef 100644 +--- a/include/types/proto_http.h ++++ b/include/types/proto_http.h +@@ -362,7 +362,6 @@ struct http_txn { + unsigned int flags; /* transaction flags */ + enum http_meth_t meth; /* HTTP method */ + /* 1 unused byte here */ +- short rule_deny_status; /* HTTP status from rule when denying */ + short status; /* HTTP status from the server, negative if from proxy */ + + char *uri; /* first line if log needed, NULL otherwise */ +diff --git a/src/proto_http.c b/src/proto_http.c +index 59cd5d2..6eac62b 100644 +--- a/src/proto_http.c ++++ b/src/proto_http.c +@@ -3490,10 +3490,12 @@ static int http_transform_header(struct stream* s, struct http_msg *msg, + * further processing of the request (auth, deny, ...), and defaults to + * HTTP_RULE_RES_STOP if it executed all rules or stopped on an allow, or + * HTTP_RULE_RES_CONT if the last rule was reached. It may set the TX_CLTARPIT +- * on txn->flags if it encounters a tarpit rule. ++ * on txn->flags if it encounters a tarpit rule. If <deny_status> is not NULL ++ * and a deny/tarpit rule is matched, it will be filled with this rule's deny ++ * status. + */ + enum rule_result +-http_req_get_intercept_rule(struct proxy *px, struct list *rules, struct stream *s) ++http_req_get_intercept_rule(struct proxy *px, struct list *rules, struct stream *s, int *deny_status) + { + struct session *sess = strm_sess(s); + struct http_txn *txn = s->txn; +@@ -3539,12 +3541,14 @@ resume_execution: + return HTTP_RULE_RES_STOP; + + case ACT_ACTION_DENY: +- txn->rule_deny_status = rule->deny_status; ++ if (deny_status) ++ *deny_status = rule->deny_status; + return HTTP_RULE_RES_DENY; + + case ACT_HTTP_REQ_TARPIT: + txn->flags |= TX_CLTARPIT; +- txn->rule_deny_status = rule->deny_status; ++ if (deny_status) ++ *deny_status = rule->deny_status; + return HTTP_RULE_RES_DENY; + + case ACT_HTTP_REQ_AUTH: +@@ -4303,6 +4307,7 @@ int http_process_req_common(struct stream *s, struct channel *req, int an_bit, s + struct redirect_rule *rule; + struct cond_wordlist *wl; + enum rule_result verdict; ++ int deny_status = HTTP_ERR_403; + + if (unlikely(msg->msg_state < HTTP_MSG_BODY)) { + /* we need more data */ +@@ -4323,7 +4328,7 @@ int http_process_req_common(struct stream *s, struct channel *req, int an_bit, s + + /* evaluate http-request rules */ + if (!LIST_ISEMPTY(&px->http_req_rules)) { +- verdict = http_req_get_intercept_rule(px, &px->http_req_rules, s); ++ verdict = http_req_get_intercept_rule(px, &px->http_req_rules, s, &deny_status); + + switch (verdict) { + case HTTP_RULE_RES_YIELD: /* some data miss, call the function later. */ +@@ -4369,7 +4374,7 @@ int http_process_req_common(struct stream *s, struct channel *req, int an_bit, s + + /* parse the whole stats request and extract the relevant information */ + http_handle_stats(s, req); +- verdict = http_req_get_intercept_rule(px, &px->uri_auth->http_req_rules, s); ++ verdict = http_req_get_intercept_rule(px, &px->uri_auth->http_req_rules, s, &deny_status); + /* not all actions implemented: deny, allow, auth */ + + if (verdict == HTTP_RULE_RES_DENY) /* stats http-request deny */ +@@ -4500,9 +4505,9 @@ int http_process_req_common(struct stream *s, struct channel *req, int an_bit, s + manage_client_side_cookies(s, req); + + txn->flags |= TX_CLDENY; +- txn->status = http_err_codes[txn->rule_deny_status]; ++ txn->status = http_err_codes[deny_status]; + s->logs.tv_request = now; +- stream_int_retnclose(&s->si[0], http_error_message(s, txn->rule_deny_status)); ++ stream_int_retnclose(&s->si[0], http_error_message(s, deny_status)); + stream_inc_http_err_ctr(s); + sess->fe->fe_counters.denied_req++; + if (sess->fe != s->be) Modified: PKGBUILD =================================================================== --- PKGBUILD 2016-06-10 06:21:51 UTC (rev 179092) +++ PKGBUILD 2016-06-10 06:23:08 UTC (rev 179093) @@ -4,7 +4,7 @@ pkgname=haproxy pkgver=1.6.5 -pkgrel=3 +pkgrel=4 pkgdesc='Reliable, high performance TCP/HTTP load balancer' url='http://haproxy.org/' @@ -19,16 +19,19 @@ source=(http://haproxy.org/download/${pkgver%.*}/src/haproxy-$pkgver.tar.gz haproxy.cfg - gcc6-fix.patch) + gcc6-fix.patch + CVE-2016-5360-reqdeny.patch) md5sums=('5290f278c04e682e42ab71fed26fc082' '02241a8ca257d12f7eb131e2d7da3f3b' - 'c4b4fba82b6f33270ed57514ed3f53e8') + 'c4b4fba82b6f33270ed57514ed3f53e8' + '24c814e197627f30b41f89ae10b8520f') prepare() { cd haproxy-$pkgver sed -i 's:/usr/sbin/haproxy:/usr/bin/haproxy:' src/haproxy-systemd-wrapper.c patch -p1 -i "$srcdir"/gcc6-fix.patch + patch -p1 -i "$srcdir"/CVE-2016-5360-reqdeny.patch } build() {