Description: fix incorrect cookie handling via partial literal IP addresses
Origin: upstream, http://curl.haxx.se/CVE-2014-3613.patch

Warning: this patch contain weird line endings, be careful when editing

Index: curl-7.37.1/lib/cookie.c
===================================================================
--- curl-7.37.1.orig/lib/cookie.c	2014-06-11 13:52:29.000000000 -0400
+++ curl-7.37.1/lib/cookie.c	2014-09-11 08:10:28.583232398 -0400
@@ -95,6 +95,7 @@
 #include "strtoofft.h"
 #include "rawstr.h"
 #include "curl_memrchr.h"
+#include "inet_pton.h"
 
 /* The last #include file should be: */
 #include "memdebug.h"
@@ -319,6 +320,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()
@@ -439,24 +462,27 @@
           }
         }
         else if(Curl_raw_equal("domain", name)) {
+          bool is_ip;
+
           /* Now, we make sure that our host is within the given domain,
              or the given domain is not valid and thus cannot be set. */
 
           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
@@ -968,6 +994,7 @@
   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 */
@@ -975,6 +1002,9 @@
   /* at first, remove expired cookies */
   remove_expired(c);
 
+  /* check if host is an IP(v4|v6) address */
+  is_ip = isip(host);
+
   co = c->cookies;
 
   while(co) {
@@ -986,8 +1016,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 */
 
Index: curl-7.37.1/tests/data/test1105
===================================================================
--- curl-7.37.1.orig/tests/data/test1105	2014-06-11 13:52:29.000000000 -0400
+++ curl-7.37.1/tests/data/test1105	2014-09-11 08:10:28.583232398 -0400
@@ -59,8 +59,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>
Index: curl-7.37.1/tests/data/test31
===================================================================
--- curl-7.37.1.orig/tests/data/test31	2014-06-11 13:52:30.000000000 -0400
+++ curl-7.37.1/tests/data/test31	2014-09-11 08:13:35.311233452 -0400
@@ -51,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>
@@ -95,34 +96,34 @@
 # http://curl.haxx.se/docs/http-cookies.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	/overwrite	FALSE	0	overwrite	this2
-.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	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>
Index: curl-7.37.1/tests/data/test8
===================================================================
--- curl-7.37.1.orig/tests/data/test8	2014-06-11 13:52:30.000000000 -0400
+++ curl-7.37.1/tests/data/test8	2014-09-11 08:10:28.583232398 -0400
@@ -42,7 +42,8 @@
 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>
