summaryrefslogtreecommitdiffstats
path: root/meta/recipes-support/curl/curl/CVE-2022-32205.patch
blob: 165fd8af478328288f7542f11064e2643acaa863 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
From a91c22a072cbb32e296f1efba3502f1b7775dfaf Mon Sep 17 00:00:00 2001
From: Daniel Stenberg <daniel@haxx.se>
Date: Sun, 26 Jun 2022 11:00:48 +0200
Subject: [PATCH] cookie: apply limits

- Send no more than 150 cookies per request
- Cap the max length used for a cookie: header to 8K
- Cap the max number of received Set-Cookie: headers to 50

Bug: https://curl.se/docs/CVE-2022-32205.html
CVE-2022-32205
Reported-by: Harry Sintonen
Closes #9048

Upstream-Status: Backport [https://github.com/curl/curl/commit/48d7064a49148f0394]
Signed-off-by: Robert Joslyn <robert.joslyn@redrectangle.org>
---
 lib/cookie.c  | 14 ++++++++++++--
 lib/cookie.h  | 21 +++++++++++++++++++--
 lib/http.c    | 13 +++++++++++--
 lib/urldata.h |  1 +
 4 files changed, 43 insertions(+), 6 deletions(-)

diff --git a/lib/cookie.c b/lib/cookie.c
index 1b8c8f9..8a6aa1a 100644
--- a/lib/cookie.c
+++ b/lib/cookie.c
@@ -477,6 +477,10 @@ Curl_cookie_add(struct Curl_easy *data,
   (void)data;
 #endif
 
+  DEBUGASSERT(MAX_SET_COOKIE_AMOUNT <= 255); /* counter is an unsigned char */
+  if(data->req.setcookies >= MAX_SET_COOKIE_AMOUNT)
+    return NULL;
+
   /* First, alloc and init a new struct for it */
   co = calloc(1, sizeof(struct Cookie));
   if(!co)
@@ -816,7 +820,7 @@ Curl_cookie_add(struct Curl_easy *data,
       freecookie(co);
       return NULL;
     }
-
+    data->req.setcookies++;
   }
   else {
     /*
@@ -1354,7 +1358,8 @@ static struct Cookie *dup_cookie(struct Cookie *src)
  *
  * It shall only return cookies that haven't expired.
  */
-struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
+struct Cookie *Curl_cookie_getlist(struct Curl_easy *data,
+                                   struct CookieInfo *c,
                                    const char *host, const char *path,
                                    bool secure)
 {
@@ -1409,6 +1414,11 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
             mainco = newco;
 
             matches++;
+            if(matches >= MAX_COOKIE_SEND_AMOUNT) {
+              infof(data, "Included max number of cookies (%u) in request!",
+                    matches);
+              break;
+            }
           }
           else
             goto fail;
diff --git a/lib/cookie.h b/lib/cookie.h
index 0ffe08e..7411980 100644
--- a/lib/cookie.h
+++ b/lib/cookie.h
@@ -81,10 +81,26 @@ struct CookieInfo {
 */
 #define MAX_COOKIE_LINE 5000
 
-/* This is the maximum length of a cookie name or content we deal with: */
+/* Maximum length of an incoming cookie name or content we deal with. Longer
+   cookies are ignored. */
 #define MAX_NAME 4096
 #define MAX_NAME_TXT "4095"
 
+/* Maximum size for an outgoing cookie line libcurl will use in an http
+   request. This is the default maximum length used in some versions of Apache
+   httpd. */
+#define MAX_COOKIE_HEADER_LEN 8190
+
+/* Maximum number of cookies libcurl will send in a single request, even if
+   there might be more cookies that match. One reason to cap the number is to
+   keep the maximum HTTP request within the maximum allowed size. */
+#define MAX_COOKIE_SEND_AMOUNT 150
+
+/* Maximum number of Set-Cookie: lines accepted in a single response. If more
+   such header lines are received, they are ignored. This value must be less
+   than 256 since an unsigned char is used to count. */
+#define MAX_SET_COOKIE_AMOUNT 50
+
 struct Curl_easy;
 /*
  * Add a cookie to the internal list of cookies. The domain and path arguments
@@ -97,7 +113,8 @@ struct Cookie *Curl_cookie_add(struct Curl_easy *data,
                                const char *domain, const char *path,
                                bool secure);
 
-struct Cookie *Curl_cookie_getlist(struct CookieInfo *c, const char *host,
+struct Cookie *Curl_cookie_getlist(struct Curl_easy *data,
+                                   struct CookieInfo *c, const char *host,
                                    const char *path, bool secure);
 void Curl_cookie_freelist(struct Cookie *cookies);
 void Curl_cookie_clearall(struct CookieInfo *cookies);
diff --git a/lib/http.c b/lib/http.c
index 4433824..2c8b0c4 100644
--- a/lib/http.c
+++ b/lib/http.c
@@ -2709,12 +2709,14 @@ CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn,
 }
 
 #if !defined(CURL_DISABLE_COOKIES)
+
 CURLcode Curl_http_cookies(struct Curl_easy *data,
                            struct connectdata *conn,
                            struct dynbuf *r)
 {
   CURLcode result = CURLE_OK;
   char *addcookies = NULL;
+  bool linecap = FALSE;
   if(data->set.str[STRING_COOKIE] &&
      !Curl_checkheaders(data, STRCONST("Cookie")))
     addcookies = data->set.str[STRING_COOKIE];
@@ -2732,7 +2734,7 @@ CURLcode Curl_http_cookies(struct Curl_easy *data,
         !strcmp(host, "127.0.0.1") ||
         !strcmp(host, "[::1]") ? TRUE : FALSE;
       Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
-      co = Curl_cookie_getlist(data->cookies, host, data->state.up.path,
+      co = Curl_cookie_getlist(data, data->cookies, host, data->state.up.path,
                                secure_context);
       Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
     }
@@ -2746,6 +2748,13 @@ CURLcode Curl_http_cookies(struct Curl_easy *data,
             if(result)
               break;
           }
+          if((Curl_dyn_len(r) + strlen(co->name) + strlen(co->value) + 1) >=
+             MAX_COOKIE_HEADER_LEN) {
+            infof(data, "Restricted outgoing cookies due to header size, "
+                  "'%s' not sent", co->name);
+            linecap = TRUE;
+            break;
+          }
           result = Curl_dyn_addf(r, "%s%s=%s", count?"; ":"",
                                  co->name, co->value);
           if(result)
@@ -2756,7 +2765,7 @@ CURLcode Curl_http_cookies(struct Curl_easy *data,
       }
       Curl_cookie_freelist(store);
     }
-    if(addcookies && !result) {
+    if(addcookies && !result && !linecap) {
       if(!count)
         result = Curl_dyn_addn(r, STRCONST("Cookie: "));
       if(!result) {
diff --git a/lib/urldata.h b/lib/urldata.h
index e006495..54faf7d 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -707,6 +707,7 @@ struct SingleRequest {
 #ifndef CURL_DISABLE_DOH
   struct dohdata *doh; /* DoH specific data for this request */
 #endif
+  unsigned char setcookies;
   BIT(header);        /* incoming data has HTTP header */
   BIT(content_range); /* set TRUE if Content-Range: was found */
   BIT(upload_done);   /* set to TRUE when doing chunked transfer-encoding