Package: release.debian.org
Severity: normal
User: release.debian....@packages.debian.org
Usertags: unblock

Dear Release Team,

Please unblock package openconnect, version 3.20-3 already uploaded to
unstable. This upload fixes RC bug #700794 (CVE-2012-6128), a
stack-based buffer overflow vulnerability.

The fix was made upstream and this change is a backport of that patch to
version 3.20. The debdiff is included below. Thanks in advance.


diffstat for openconnect-3.20 openconnect-3.20

 changelog                      |    7 +
 patches/02_CVE-2012-6128.patch |  281 +++++++++++++++++++++++++++++++++++++++++
 patches/series                 |    1 
 3 files changed, 289 insertions(+)

diff -Nru openconnect-3.20/debian/changelog openconnect-3.20/debian/changelog
--- openconnect-3.20/debian/changelog   2012-06-06 08:54:48.000000000 -0400
+++ openconnect-3.20/debian/changelog   2013-02-17 12:25:52.000000000 -0500
@@ -1,3 +1,10 @@
+openconnect (3.20-3) unstable; urgency=low
+
+  * debian/patches/02_CVE-2012-6128.patch: Backport patch from upstream to fix
+    buffer overflow (CVE-2012-6128). (Closes: #700794)
+
+ -- Mike Miller <mtmil...@ieee.org>  Sun, 17 Feb 2013 11:56:35 -0500
+
 openconnect (3.20-2) unstable; urgency=low
 
   * Depend on vpnc-scripts for routing and DNS configuration. (Closes:
diff -Nru openconnect-3.20/debian/patches/02_CVE-2012-6128.patch 
openconnect-3.20/debian/patches/02_CVE-2012-6128.patch
--- openconnect-3.20/debian/patches/02_CVE-2012-6128.patch      1969-12-31 
19:00:00.000000000 -0500
+++ openconnect-3.20/debian/patches/02_CVE-2012-6128.patch      2013-02-17 
12:25:52.000000000 -0500
@@ -0,0 +1,281 @@
+Origin: upstream, 
http://git.infradead.org/users/dwmw2/openconnect.git/commitdiff/26f752c3dbf69227679fc6bebb4ae071aecec491
+From: Kevin Cernekee <cerne...@gmail.com>
+Subject: http: Fix overflow on HTTP request buffers
+
+A malicious VPN gateway can send a very long hostname/path (for redirects)
+or cookie list (in general), which OpenConnect will attempt to sprintf()
+into a fixed length buffer.  Each HTTP server response line can add
+roughly MAX_BUF_LEN (131072) bytes to the next OpenConnect HTTP request,
+but the request buffer (buf) is capped at MAX_BUF_LEN bytes and is
+allocated on the stack.
+
+The result of passing a long "Location:" header looks like:
+
+    Attempting to connect to server 127.0.0.1:443
+    SSL negotiation with localhost
+    Server certificate verify failed: self signed certificate in certificate 
chain
+    Connected to HTTPS on localhost
+    GET https://localhost/
+    Got HTTP response: HTTP/1.0 301 Moved
+    Ignoring unknown HTTP response line 'aaaaaaaaaaaaaaaaaa'
+    SSL negotiation with localhost
+    Server certificate verify failed: self signed certificate in certificate 
chain
+    Connected to HTTPS on localhost
+    *** buffer overflow detected ***: /scr/openconnect2/.libs/lt-openconnect 
terminated
+    ======= Backtrace: =========
+    /lib/x86_64-linux-gnu/libc.so.6(__fortify_fail+0x5c)[0x7fd62729b82c]
+    /lib/x86_64-linux-gnu/libc.so.6(+0x109700)[0x7fd62729a700]
+    /lib/x86_64-linux-gnu/libc.so.6(+0x108b69)[0x7fd627299b69]
+    /lib/x86_64-linux-gnu/libc.so.6(_IO_default_xsputn+0xdd)[0x7fd62720d13d]
+    /lib/x86_64-linux-gnu/libc.so.6(_IO_vfprintf+0x1ae7)[0x7fd6271db4a7]
+    /lib/x86_64-linux-gnu/libc.so.6(__vsprintf_chk+0x94)[0x7fd627299c04]
+    /lib/x86_64-linux-gnu/libc.so.6(__sprintf_chk+0x7d)[0x7fd627299b4d]
+    
/scr/openconnect2/.libs/libopenconnect.so.2(openconnect_obtain_cookie+0xc0)[0x7fd62832d210]
+    /scr/openconnect2/.libs/lt-openconnect[0x40413f]
+    /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed)[0x7fd6271b276d]
+    /scr/openconnect2/.libs/lt-openconnect[0x404579]
+
+The proposed fix is to use dynamically allocated buffers with overflow
+checking.
+
+--- a/http.c
++++ b/http.c
+@@ -32,6 +32,7 @@
+ #include <pwd.h>
+ #include <sys/stat.h>
+ #include <sys/types.h>
++#include <stdarg.h>
+ 
+ #include <openssl/ssl.h>
+ #include <openssl/err.h>
+@@ -45,6 +46,85 @@ static int proxy_read(struct openconnect
+                     unsigned char *buf, size_t len);
+ 
+ #define MAX_BUF_LEN 131072
++#define BUF_CHUNK_SIZE 4096
++
++struct oc_text_buf {
++      char *data;
++      int pos;
++      int buf_len;
++      int error;
++};
++
++static struct oc_text_buf *buf_alloc(void)
++{
++      return calloc(1, sizeof(struct oc_text_buf));
++}
++
++static void buf_append(struct oc_text_buf *buf, const char *fmt, ...)
++{
++      va_list ap;
++
++      if (!buf || buf->error)
++              return;
++
++      if (!buf->data) {
++              buf->data = malloc(BUF_CHUNK_SIZE);
++              if (!buf->data) {
++                      buf->error = -ENOMEM;
++                      return;
++              }
++              buf->buf_len = BUF_CHUNK_SIZE;
++      }
++
++      while (1) {
++              int max_len = buf->buf_len - buf->pos, ret;
++
++              va_start(ap, fmt);
++              ret = vsnprintf(buf->data + buf->pos, max_len, fmt, ap);
++              va_end(ap);
++              if (ret < 0) {
++                      buf->error = -EIO;
++                      break;
++              } else if (ret < max_len) {
++                      buf->pos += ret;
++                      break;
++              } else {
++                      int new_buf_len = buf->buf_len + BUF_CHUNK_SIZE;
++
++                      if (new_buf_len > MAX_BUF_LEN) {
++                              /* probably means somebody is messing with us */
++                              buf->error = -E2BIG;
++                              break;
++                      }
++
++                      buf->data = realloc(buf->data, new_buf_len);
++                      if (!buf->data) {
++                              buf->error = -ENOMEM;
++                              break;
++                      }
++                      buf->buf_len = new_buf_len;
++              }
++      }
++}
++
++static int buf_error(struct oc_text_buf *buf)
++{
++      return buf ? buf->error : -ENOMEM;
++}
++
++static int buf_free(struct oc_text_buf *buf)
++{
++      int error = buf_error(buf);
++
++      if (buf) {
++              if (buf->data)
++                      free(buf->data);
++              free(buf);
++      }
++
++      return error;
++}
++
+ /*
+  * We didn't really want to have to do this for ourselves -- one might have
+  * thought that it would be available in a library somewhere. But neither
+@@ -352,7 +432,7 @@ static int fetch_config(struct openconne
+                       char *server_sha1)
+ {
+       struct vpn_option *opt;
+-      char buf[MAX_BUF_LEN];
++      struct oc_text_buf *buf;
+       char *config_buf = NULL;
+       int result, buflen;
+       unsigned char local_sha1_bin[SHA_DIGEST_LENGTH];
+@@ -360,21 +440,26 @@ static int fetch_config(struct openconne
+       EVP_MD_CTX c;
+       int i;
+ 
+-      sprintf(buf, "GET %s%s HTTP/1.1\r\n", fu, bu);
+-      sprintf(buf + strlen(buf), "Host: %s\r\n", vpninfo->hostname);
+-      sprintf(buf + strlen(buf),  "User-Agent: %s\r\n", vpninfo->useragent);
+-      sprintf(buf + strlen(buf),  "Accept: */*\r\n");
+-      sprintf(buf + strlen(buf),  "Accept-Encoding: identity\r\n");
++      buf = buf_alloc();
++      buf_append(buf, "GET %s%s HTTP/1.1\r\n", fu, bu);
++      buf_append(buf, "Host: %s\r\n", vpninfo->hostname);
++      buf_append(buf, "User-Agent: %s\r\n", vpninfo->useragent);
++      buf_append(buf, "Accept: */*\r\n");
++      buf_append(buf, "Accept-Encoding: identity\r\n");
+ 
+       if (vpninfo->cookies) {
+-              sprintf(buf + strlen(buf),  "Cookie: ");
++              buf_append(buf, "Cookie: ");
+               for (opt = vpninfo->cookies; opt; opt = opt->next)
+-                      sprintf(buf + strlen(buf),  "%s=%s%s", opt->option,
++                      buf_append(buf, "%s=%s%s", opt->option,
+                                     opt->value, opt->next ? "; " : "\r\n");
+       }
+-      sprintf(buf + strlen(buf),  "X-Transcend-Version: 1\r\n\r\n");
++      buf_append(buf, "X-Transcend-Version: 1\r\n\r\n");
++
++      if (buf_error(buf))
++              return buf_free(buf);
+ 
+-      SSL_write(vpninfo->https_ssl, buf, strlen(buf));
++      SSL_write(vpninfo->https_ssl, buf->data, buf->pos);
++      buf_free(buf);
+ 
+       buflen = process_http_response(vpninfo, &result, NULL, &config_buf);
+       if (buflen < 0) {
+@@ -630,7 +715,7 @@ int internal_parse_url(char *url, char *
+ int openconnect_obtain_cookie(struct openconnect_info *vpninfo)
+ {
+       struct vpn_option *opt, *next;
+-      char buf[MAX_BUF_LEN];
++      struct oc_text_buf *buf;
+       char *form_buf = NULL;
+       int result, buflen;
+       char request_body[2048];
+@@ -658,27 +743,26 @@ int openconnect_obtain_cookie(struct ope
+        *
+        * So we process the HTTP for ourselves...
+        */
+-      sprintf(buf, "%s /%s HTTP/1.1\r\n", method, vpninfo->urlpath ?: "");
+-      sprintf(buf + strlen(buf), "Host: %s\r\n", vpninfo->hostname);
+-      sprintf(buf + strlen(buf),  "User-Agent: %s\r\n", vpninfo->useragent);
+-      sprintf(buf + strlen(buf),  "Accept: */*\r\n");
+-      sprintf(buf + strlen(buf),  "Accept-Encoding: identity\r\n");
++      buf = buf_alloc();
++      buf_append(buf, "%s /%s HTTP/1.1\r\n", method, vpninfo->urlpath ?: "");
++      buf_append(buf, "Host: %s\r\n", vpninfo->hostname);
++      buf_append(buf, "User-Agent: %s\r\n", vpninfo->useragent);
++      buf_append(buf, "Accept: */*\r\n");
++      buf_append(buf, "Accept-Encoding: identity\r\n");
+ 
+       if (vpninfo->cookies) {
+-              sprintf(buf + strlen(buf),  "Cookie: ");
++              buf_append(buf, "Cookie: ");
+               for (opt = vpninfo->cookies; opt; opt = opt->next)
+-                      sprintf(buf + strlen(buf),  "%s=%s%s", opt->option,
+-                                    opt->value, opt->next ? "; " : "\r\n");
++                      buf_append(buf, "%s=%s%s", opt->option,
++                                 opt->value, opt->next ? "; " : "\r\n");
+       }
+       if (request_body_type) {
+-              sprintf(buf + strlen(buf),  "Content-Type: %s\r\n",
+-                            request_body_type);
+-              sprintf(buf + strlen(buf),  "Content-Length: %zd\r\n",
+-                            strlen(request_body));
++              buf_append(buf, "Content-Type: %s\r\n", request_body_type);
++              buf_append(buf, "Content-Length: %zd\r\n", 
strlen(request_body));
+       }
+-      sprintf(buf + strlen(buf),  "X-Transcend-Version: 1\r\n\r\n");
++      buf_append(buf, "X-Transcend-Version: 1\r\n\r\n");
+       if (request_body_type)
+-              sprintf(buf + strlen(buf), "%s", request_body);
++              buf_append(buf, "%s", request_body);
+ 
+       if (vpninfo->port == 443)
+               vpn_progress(vpninfo, PRG_INFO, "%s https://%s/%s\n";,
+@@ -689,7 +773,11 @@ int openconnect_obtain_cookie(struct ope
+                            method, vpninfo->hostname, vpninfo->port,
+                            vpninfo->urlpath ?: "");
+ 
+-      result = openconnect_SSL_write(vpninfo, buf, strlen(buf));
++      if (buf_error(buf))
++              return buf_free(buf);
++
++      result = openconnect_SSL_write(vpninfo, buf->data, buf->pos);
++      buf_free(buf);
+       if (result < 0)
+               return result;
+ 
+@@ -1114,21 +1202,28 @@ static int process_socks_proxy(struct op
+ static int process_http_proxy(struct openconnect_info *vpninfo, int ssl_sock)
+ {
+       char buf[MAX_BUF_LEN];
++      struct oc_text_buf *reqbuf;
+       int buflen, result;
+ 
+-      sprintf(buf, "CONNECT %s:%d HTTP/1.1\r\n", vpninfo->hostname, 
vpninfo->port);
+-      sprintf(buf + strlen(buf), "Host: %s\r\n", vpninfo->hostname);
+-      sprintf(buf + strlen(buf), "User-Agent: %s\r\n", vpninfo->useragent);
+-      sprintf(buf + strlen(buf), "Proxy-Connection: keep-alive\r\n");
+-      sprintf(buf + strlen(buf), "Connection: keep-alive\r\n");
+-      sprintf(buf + strlen(buf), "Accept-Encoding: identity\r\n");
+-      sprintf(buf + strlen(buf), "\r\n");
++      reqbuf = buf_alloc();
++      buf_append(reqbuf, "CONNECT %s:%d HTTP/1.1\r\n", vpninfo->hostname, 
vpninfo->port);
++      buf_append(reqbuf, "Host: %s\r\n", vpninfo->hostname);
++      buf_append(reqbuf, "User-Agent: %s\r\n", vpninfo->useragent);
++      buf_append(reqbuf, "Proxy-Connection: keep-alive\r\n");
++      buf_append(reqbuf, "Connection: keep-alive\r\n");
++      buf_append(reqbuf, "Accept-Encoding: identity\r\n");
++      buf_append(reqbuf, "\r\n");
++
++      if (buf_error(reqbuf))
++              return buf_free(reqbuf);
+ 
+       vpn_progress(vpninfo, PRG_INFO,
+                    _("Requesting HTTP proxy connection to %s:%d\n"),
+                    vpninfo->hostname, vpninfo->port);
+ 
+-      result = proxy_write(vpninfo, ssl_sock, (unsigned char *)buf, 
strlen(buf));
++      result = proxy_write(vpninfo, ssl_sock, (unsigned char *)reqbuf->data, 
reqbuf->pos);
++      buf_free(reqbuf);
++
+       if (result) {
+               vpn_progress(vpninfo, PRG_ERR,
+                            _("Sending proxy request failed: %s\n"),
diff -Nru openconnect-3.20/debian/patches/series 
openconnect-3.20/debian/patches/series
--- openconnect-3.20/debian/patches/series      2012-06-06 08:54:48.000000000 
-0400
+++ openconnect-3.20/debian/patches/series      2013-02-17 12:25:52.000000000 
-0500
@@ -1 +1,2 @@
 01_man-vpnc-script-path.patch
+02_CVE-2012-6128.patch


-- 
To UNSUBSCRIBE, email to debian-bugs-dist-requ...@lists.debian.org
with a subject of "unsubscribe". Trouble? Contact listmas...@lists.debian.org

Reply via email to