19548009 problem in LIBRARY/CURL
authorRich Burridge <rich.burridge@oracle.com>
Wed, 10 Sep 2014 08:54:16 -0700
changeset 2077 6efd64347fb0
parent 2076 451fed2162a2
child 2078 86a0793d713a
19548009 problem in LIBRARY/CURL
components/curl/patches/014-CVE-2014-3613-part1.patch
components/curl/patches/014-CVE-2014-3613-part2.patch
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/curl/patches/014-CVE-2014-3613-part1.patch	Wed Sep 10 08:54:16 2014 -0700
@@ -0,0 +1,301 @@
+From eac573ea9c368f5e3c07de4d5ec5c5d0f84a021a Mon Sep 17 00:00:00 2001
+From: Tim Ruehsen <[email protected]>
+Date: Tue, 19 Aug 2014 21:01:28 +0200
+Subject: [PATCH 1/2] cookies: only use full host matches for hosts used as IP
+ address
+
+By not detecting and rejecting domain names for partial literal IP
+addresses properly when parsing received HTTP cookies, libcurl can be
+fooled to both send cookies to wrong sites and to allow arbitrary sites
+to set cookies for others.
+
+Bug: http://curl.haxx.se/docs/adv_20140910.html
+---
+ lib/cookie.c        | 50 ++++++++++++++++++++++++++++++++++++++----------
+ tests/data/test1105 |  3 +--
+ tests/data/test31   | 55 +++++++++++++++++++++++++++--------------------------
+ tests/data/test8    |  3 ++-
+ 4 files changed, 71 insertions(+), 40 deletions(-)
+
+This problem has been fixed upstream in curl version 7.38.0
+
+--- lib/cookie.c.orig	2014-09-02 16:10:55.940825864 -0700
++++ lib/cookie.c	2014-09-02 16:32:39.899617696 -0700
+@@ -94,6 +94,7 @@
+ #include "strtoofft.h"
+ #include "rawstr.h"
+ #include "curl_memrchr.h"
++#include "inet_pton.h"
+ 
+ /* The last #include file should be: */
+ #include "memdebug.h"
+@@ -178,6 +179,28 @@
+ }
+ 
+ 
++/*
++ * Return true if the given string is an IP(v4|v6) address.
++ */
++static bool isip(const char *domain)
++{
++  struct in_addr addr;
++#ifdef ENABLE_IPV6
++  struct in6_addr addr6;
++#endif
++
++  if(Curl_inet_pton(AF_INET, domain, &addr)
++#ifdef ENABLE_IPV6
++     || Curl_inet_pton(AF_INET6, domain, &addr6)
++#endif
++    ) {
++    /* domain name given as IP address */
++    return TRUE;
++  }
++
++  return FALSE;
++}
++
+ /****************************************************************************
+  *
+  * Curl_cookie_add()
+@@ -290,6 +313,8 @@
+           }
+         }
+         else if(Curl_raw_equal("domain", name)) {
++          bool is_ip;
++
+           /* note that this name may or may not have a preceding dot, but
+              we don't care about that, we treat the names the same anyway */
+ 
+@@ -333,18 +358,19 @@
+             if('.' == whatptr[0])
+               whatptr++; /* ignore preceding dot */
+ 
+-            if(!domain || tailmatch(whatptr, domain)) {
+-              const char *tailptr=whatptr;
+-              if(tailptr[0] == '.')
+-                tailptr++;
+-              strstore(&co->domain, tailptr); /* don't prefix w/dots
+-                                                 internally */
++            is_ip = isip(domain ? domain : whatptr);
++
++            if(!domain
++               || (is_ip && !strcmp(whatptr, domain))
++               || (!is_ip && tailmatch(whatptr, domain))) {
++              strstore(&co->domain, whatptr);
+               if(!co->domain) {
+                 badcookie = TRUE;
+                 break;
+               }
+-              co->tailmatch=TRUE; /* we always do that if the domain name was
+-                                     given */
++              if(!is_ip)
++                co->tailmatch=TRUE; /* we always do that if the domain name was
++                                       given */
+             }
+             else {
+               /* we did not get a tailmatch and then the attempted set domain
+@@ -819,10 +845,14 @@
+   time_t now = time(NULL);
+   struct Cookie *mainco=NULL;
+   size_t matches = 0;
++  bool is_ip;
+ 
+   if(!c || !c->cookies)
+     return NULL; /* no cookie struct or no cookies in the struct */
+ 
++  /* check if host is an IP(v4|v6) address */
++  is_ip = isip(host);
++
+   co = c->cookies;
+ 
+   while(co) {
+@@ -834,8 +864,8 @@
+ 
+       /* now check if the domain is correct */
+       if(!co->domain ||
+-         (co->tailmatch && tailmatch(co->domain, host)) ||
+-         (!co->tailmatch && Curl_raw_equal(host, co->domain)) ) {
++         (co->tailmatch && !is_ip && tailmatch(co->domain, host)) ||
++         ((!co->tailmatch || is_ip) && Curl_raw_equal(host, co->domain)) ) {
+         /* the right part of the host matches the domain stuff in the
+            cookie data */
+ 
+--- tests/data/test1105.orig	2014-09-02 16:11:45.732615643 -0700
++++ tests/data/test1105	2014-09-02 16:33:42.523906352 -0700
+@@ -56,8 +56,7 @@
+ # This file was generated by libcurl! Edit at your own risk.
+ 
+ 127.0.0.1	FALSE	/we/want/	FALSE	0	foobar	name
+-.127.0.0.1	TRUE	"/silly/"	FALSE	0	mismatch	this
+-.0.0.1	TRUE	/	FALSE	0	partmatch	present
++127.0.0.1	FALSE	"/silly/"	FALSE	0	mismatch	this
+ </file>
+ </verify>
+ </testcase>
+--- tests/data/test31.orig	2014-09-02 16:11:56.912528200 -0700
++++ tests/data/test31	2014-09-04 06:13:16.741533782 -0700
+@@ -18,27 +18,29 @@
+ Funny-head: yesyes
+ Set-Cookie: foobar=name; domain=anything.com; path=/ ; secure
+ Set-Cookie:ismatch=this  ; domain=127.0.0.1; path=/silly/
++Set-Cookie: overwrite=this  ; domain=127.0.0.1; path=/overwrite/
++Set-Cookie: overwrite=this2  ; domain=127.0.0.1; path=/overwrite
+ Set-Cookie: sec1value=secure1  ; domain=127.0.0.1; path=/secure1/ ; secure
+ Set-Cookie: sec2value=secure2  ; domain=127.0.0.1; path=/secure2/ ; secure=
+ Set-Cookie: sec3value=secure3  ; domain=127.0.0.1; path=/secure3/ ; secure=
+-Set-Cookie: sec4value=secure4  ; secure=; domain=127.0.0.1; path=/secure4/ ; 
+-Set-Cookie: sec5value=secure5  ; secure; domain=127.0.0.1; path=/secure5/ ; 
+-Set-Cookie: sec6value=secure6  ; secure ; domain=127.0.0.1; path=/secure6/ ; 
+-Set-Cookie: sec7value=secure7  ; secure   ; domain=127.0.0.1; path=/secure7/ ; 
+-Set-Cookie: sec8value=secure8  ; secure= ; domain=127.0.0.1; path=/secure8/ ; 
+-Set-Cookie: secure=very1  ; secure=; domain=127.0.0.1; path=/secure9/; 
+-Set-Cookie: httpo1=value1  ; domain=127.0.0.1; path=/p1/; httponly
+-Set-Cookie: httpo2=value2  ; domain=127.0.0.1; path=/p2/; httponly=
+-Set-Cookie: httpo3=value3  ; httponly; domain=127.0.0.1; path=/p3/;
+-Set-Cookie: httpo4=value4  ; httponly=; domain=127.0.0.1; path=/p4/; 
+-Set-Cookie: httponly=myvalue1  ; domain=127.0.0.1; path=/p4/; httponly
+-Set-Cookie: httpandsec=myvalue2  ; domain=127.0.0.1; path=/p4/; httponly; secure
+-Set-Cookie: httpandsec2=myvalue3; domain=127.0.0.1; path=/p4/; httponly=; secure
+-Set-Cookie: httpandsec3=myvalue4  ; domain=127.0.0.1; path=/p4/; httponly; secure=
+-Set-Cookie: httpandsec4=myvalue5  ; domain=127.0.0.1; path=/p4/; httponly=; secure=
+-Set-Cookie: httpandsec5=myvalue6  ; domain=127.0.0.1; path=/p4/; secure; httponly=
+-Set-Cookie: httpandsec6=myvalue7  ; domain=127.0.0.1; path=/p4/; secure=; httponly=
+-Set-Cookie: httpandsec7=myvalue8  ; domain=127.0.0.1; path=/p4/; secure; httponly
++Set-Cookie: sec4value=secure4  ; secure=; domain=127.0.0.1; path=/secure4/ ; 
++Set-Cookie: sec5value=secure5  ; secure; domain=127.0.0.1; path=/secure5/ ; 
++Set-Cookie: sec6value=secure6  ; secure ; domain=127.0.0.1; path=/secure6/ ; 
++Set-Cookie: sec7value=secure7  ; secure   ; domain=127.0.0.1; path=/secure7/ ; 
++Set-Cookie: sec8value=secure8  ; secure= ; domain=127.0.0.1; path=/secure8/ ; 
++Set-Cookie: secure=very1  ; secure=; domain=127.0.0.1; path=/secure9/; 
++Set-Cookie: httpo1=value1  ; domain=127.0.0.1; path=/p1/; httponly
++Set-Cookie: httpo2=value2  ; domain=127.0.0.1; path=/p2/; httponly=
++Set-Cookie: httpo3=value3  ; httponly; domain=127.0.0.1; path=/p3/;
++Set-Cookie: httpo4=value4  ; httponly=; domain=127.0.0.1; path=/p4/; 
++Set-Cookie: httponly=myvalue1  ; domain=127.0.0.1; path=/p4/; httponly
++Set-Cookie: httpandsec=myvalue2  ; domain=127.0.0.1; path=/p4/; httponly; secure
++Set-Cookie: httpandsec2=myvalue3; domain=127.0.0.1; path=/p4/; httponly=; secure
++Set-Cookie: httpandsec3=myvalue4  ; domain=127.0.0.1; path=/p4/; httponly; secure=
++Set-Cookie: httpandsec4=myvalue5  ; domain=127.0.0.1; path=/p4/; httponly=; secure=
++Set-Cookie: httpandsec5=myvalue6  ; domain=127.0.0.1; path=/p4/; secure; httponly=
++Set-Cookie: httpandsec6=myvalue7  ; domain=127.0.0.1; path=/p4/; secure=; httponly=
++Set-Cookie: httpandsec7=myvalue8  ; domain=127.0.0.1; path=/p4/; secure; httponly
+ Set-Cookie: httpandsec8=myvalue9; domain=127.0.0.1; path=/p4/; secure=; httponly
+ Set-Cookie: partmatch=present; domain=127.0.0.1 ; path=/;
+ Set-Cookie:eat=this; domain=moo.foo.moo;
+@@ -49,7 +51,8 @@
+ Set-Cookie: test=yes; domain=foo.com; expires=Sat Feb 2 11:56:27 GMT 2030
+ Set-Cookie: test2=yes; domain=se; expires=Sat Feb 2 11:56:27 GMT 2030
+ Set-Cookie: magic=yessir; path=/silly/; HttpOnly
+-Set-Cookie: blexp=yesyes; domain=.0.0.1; domain=.0.0.1; expiry=totally bad;
++Set-Cookie: blexp=yesyes; domain=127.0.0.1; domain=127.0.0.1; expiry=totally bad;
++Set-Cookie: partialip=nono; domain=.0.0.1;
+ 
+ boo
+ </data>
+@@ -72,6 +75,9 @@
+  <command>
+ http://%HOSTIP:%HTTPPORT/we/want/31 -b none -c log/jar31.txt
+ </command>
++<precheck>
++perl -e 'if ("%HOSTIP" !~ /127\.0\.0\.1$/) {print "Test only works for HOSTIP 127.0.0.1"; exit(1)}'
++</precheck>
+ </client>
+ 
+ # Verify data after the test has been "shot"
+@@ -90,33 +96,35 @@
+ # http://curl.haxx.se/rfc/cookie_spec.html
+ # This file was generated by libcurl! Edit at your own risk.
+ 
+-.127.0.0.1	TRUE	/silly/	FALSE	0	ismatch	this
+-.127.0.0.1	TRUE	/secure1/	TRUE	0	sec1value	secure1
+-.127.0.0.1	TRUE	/secure2/	TRUE	0	sec2value	secure2
+-.127.0.0.1	TRUE	/secure3/	TRUE	0	sec3value	secure3
+-.127.0.0.1	TRUE	/secure4/	TRUE	0	sec4value	secure4
+-.127.0.0.1	TRUE	/secure5/	TRUE	0	sec5value	secure5
+-.127.0.0.1	TRUE	/secure6/	TRUE	0	sec6value	secure6
+-.127.0.0.1	TRUE	/secure7/	TRUE	0	sec7value	secure7
+-.127.0.0.1	TRUE	/secure8/	TRUE	0	sec8value	secure8
+-.127.0.0.1	TRUE	/secure9/	TRUE	0	secure	very1
+-#HttpOnly_.127.0.0.1	TRUE	/p1/	FALSE	0	httpo1	value1
+-#HttpOnly_.127.0.0.1	TRUE	/p2/	FALSE	0	httpo2	value2
+-#HttpOnly_.127.0.0.1	TRUE	/p3/	FALSE	0	httpo3	value3
+-#HttpOnly_.127.0.0.1	TRUE	/p4/	FALSE	0	httpo4	value4
+-#HttpOnly_.127.0.0.1	TRUE	/p4/	FALSE	0	httponly	myvalue1
+-#HttpOnly_.127.0.0.1	TRUE	/p4/	TRUE	0	httpandsec	myvalue2
+-#HttpOnly_.127.0.0.1	TRUE	/p4/	TRUE	0	httpandsec2	myvalue3
+-#HttpOnly_.127.0.0.1	TRUE	/p4/	TRUE	0	httpandsec3	myvalue4
+-#HttpOnly_.127.0.0.1	TRUE	/p4/	TRUE	0	httpandsec4	myvalue5
+-#HttpOnly_.127.0.0.1	TRUE	/p4/	TRUE	0	httpandsec5	myvalue6
+-#HttpOnly_.127.0.0.1	TRUE	/p4/	TRUE	0	httpandsec6	myvalue7
+-#HttpOnly_.127.0.0.1	TRUE	/p4/	TRUE	0	httpandsec7	myvalue8
+-#HttpOnly_.127.0.0.1	TRUE	/p4/	TRUE	0	httpandsec8	myvalue9
+-.127.0.0.1	TRUE	/	FALSE	0	partmatch	present
++127.0.0.1	FALSE	/silly/	FALSE	0	ismatch	this
++127.0.0.1	FALSE	/overwrite/	FALSE	0	overwrite	this
++127.0.0.1	FALSE	/overwrite	FALSE	0	overwrite	this2
++127.0.0.1	FALSE	/secure1/	TRUE	0	sec1value	secure1
++127.0.0.1	FALSE	/secure2/	TRUE	0	sec2value	secure2
++127.0.0.1	FALSE	/secure3/	TRUE	0	sec3value	secure3
++127.0.0.1	FALSE	/secure4/	TRUE	0	sec4value	secure4
++127.0.0.1	FALSE	/secure5/	TRUE	0	sec5value	secure5
++127.0.0.1	FALSE	/secure6/	TRUE	0	sec6value	secure6
++127.0.0.1	FALSE	/secure7/	TRUE	0	sec7value	secure7
++127.0.0.1	FALSE	/secure8/	TRUE	0	sec8value	secure8
++127.0.0.1	FALSE	/secure9/	TRUE	0	secure	very1
++#HttpOnly_127.0.0.1	FALSE	/p1/	FALSE	0	httpo1	value1
++#HttpOnly_127.0.0.1	FALSE	/p2/	FALSE	0	httpo2	value2
++#HttpOnly_127.0.0.1	FALSE	/p3/	FALSE	0	httpo3	value3
++#HttpOnly_127.0.0.1	FALSE	/p4/	FALSE	0	httpo4	value4
++#HttpOnly_127.0.0.1	FALSE	/p4/	FALSE	0	httponly	myvalue1
++#HttpOnly_127.0.0.1	FALSE	/p4/	TRUE	0	httpandsec	myvalue2
++#HttpOnly_127.0.0.1	FALSE	/p4/	TRUE	0	httpandsec2	myvalue3
++#HttpOnly_127.0.0.1	FALSE	/p4/	TRUE	0	httpandsec3	myvalue4
++#HttpOnly_127.0.0.1	FALSE	/p4/	TRUE	0	httpandsec4	myvalue5
++#HttpOnly_127.0.0.1	FALSE	/p4/	TRUE	0	httpandsec5	myvalue6
++#HttpOnly_127.0.0.1	FALSE	/p4/	TRUE	0	httpandsec6	myvalue7
++#HttpOnly_127.0.0.1	FALSE	/p4/	TRUE	0	httpandsec7	myvalue8
++#HttpOnly_127.0.0.1	FALSE	/p4/	TRUE	0	httpandsec8	myvalue9
++127.0.0.1	FALSE	/	FALSE	0	partmatch	present
+ 127.0.0.1	FALSE	/we/want/	FALSE	2054030187	nodomain	value
+ #HttpOnly_127.0.0.1	FALSE	/silly/	FALSE	0	magic	yessir
+-.0.0.1	TRUE	/we/want/	FALSE	0	blexp	yesyes
++127.0.0.1	FALSE	/we/want/	FALSE	0	blexp	yesyes
+ </file>
+ </verify>
+ </testcase>
+--- tests/data/test8.orig	2014-09-02 16:13:07.812626284 -0700
++++ tests/data/test8	2014-09-02 17:24:33.131678950 -0700
+@@ -35,16 +35,20 @@
+ Server: test-server/fake
+ Content-Type: text/html
+ Funny-head: yesyes
+-Set-Cookie: foobar=name; domain=127.0.0.1; path=/;
+-Set-Cookie: mismatch=this; domain=127.0.0.1; path="/silly/";
++Set-Cookie: foobar=name; domain=%HOSTIP; path=/;
++Set-Cookie: mismatch=this; domain=%HOSTIP; path="/silly/";
+ Set-Cookie: partmatch=present; domain=.0.0.1; path=/w;
+ Set-Cookie: duplicate=test; domain=.0.0.1; domain=.0.0.1; path=/donkey;
+ Set-Cookie: cookie=yes; path=/we;
+ Set-Cookie: cookie=perhaps; path=/we/want;
+ Set-Cookie: nocookie=yes; path=/WE;
+-Set-Cookie: blexp=yesyes; domain=.0.0.1; domain=.0.0.1; expiry=totally bad;
++Set-Cookie: blexp=yesyes; domain=%HOSTIP; domain=%HOSTIP; expiry=totally bad;
++Set-Cookie: partialip=nono; domain=.0.0.1;
+ 
+ </file>
++<precheck>
++perl -e 'if ("%HOSTIP" !~ /\.0\.0\.1$/) {print "Test only works for HOSTIPs ending with .0.0.1"; exit(1)}'
++</precheck>
+ </client>
+ 
+ # Verify data after the test has been "shot"
+@@ -56,7 +60,7 @@
+ GET /we/want/8 HTTP/1.1
+ Host: %HOSTIP:%HTTPPORT
+ Accept: */*
+-Cookie: cookie=perhaps; cookie=yes; partmatch=present; foobar=name; blexp=yesyes
++Cookie: cookie=perhaps; cookie=yes; foobar=name; blexp=yesyes
+ 
+ </protocol>
+ </verify>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/curl/patches/014-CVE-2014-3613-part2.patch	Wed Sep 10 08:54:16 2014 -0700
@@ -0,0 +1,47 @@
+From ceab2ea8f0c0fc4c4be219240ccf99ddc2de7b22 Mon Sep 17 00:00:00 2001
+From: Daniel Stenberg <[email protected]>
+Date: Tue, 19 Aug 2014 21:11:20 +0200
+Subject: [PATCH 2/2] cookies: reject incoming cookies set for TLDs
+
+Test 61 was modified to verify this.
+
+Reported-by: Tim Ruehsen
+---
+ lib/cookie.c      | 6 ++++++
+ tests/data/test61 | 1 +
+ 2 files changed, 7 insertions(+)
+
+This problem has been fixed upstream in curl version 7.38.0
+
+--- lib/cookie.c.orig	2014-09-02 16:45:06.782110349 -0700
++++ lib/cookie.c	2014-09-02 16:46:23.252037990 -0700
+@@ -314,6 +314,7 @@
+         }
+         else if(Curl_raw_equal("domain", name)) {
+           bool is_ip;
++          const char *dotp;
+ 
+           /* note that this name may or may not have a preceding dot, but
+              we don't care about that, we treat the names the same anyway */
+@@ -360,6 +361,11 @@
+ 
+             is_ip = isip(domain ? domain : whatptr);
+ 
++            /* check for more dots */
++            dotp = strchr(whatptr, '.');
++            if(!dotp)
++              domain=":";
++
+             if(!domain
+                || (is_ip && !strcmp(whatptr, domain))
+                || (!is_ip && tailmatch(whatptr, domain))) {
+--- tests/data/test61.orig	2014-09-02 16:22:41.267624972 -0700
++++ tests/data/test61	2014-09-02 16:47:10.419615833 -0700
+@@ -23,6 +23,7 @@
+ Set-Cookie: test4=no; domain=nope.foo.com; path=/moo; secure
+ Set-Cookie: test5=name; domain=anything.com; path=/ ; secure
+ Set-Cookie: fake=fooledyou; domain=..com; path=/;
++Set-Cookie: supercookie=fooledyou; domain=.com; path=/;
+ Content-Length: 4
+ 
+ boo