1From 076a2f629119222aeeb50f5a03bf9f9052fabb9a Mon Sep 17 00:00:00 2001 2From: Daniel Stenberg <daniel@haxx.se> 3Date: Tue, 27 Dec 2022 11:50:20 +0100 4Subject: [PATCH] share: add sharing of HSTS cache among handles 5 6Closes #10138 7 8CVE: CVE-2023-23914 CVE-2023-23915 9Upstream-Status: Backport [https://github.com/curl/curl/commit/076a2f629119222aeeb50f5a03bf9f9052fabb9a] 10Comment: Refreshed hunk from hsts.c and urldata.h 11Signed-off-by: Pawan Badganchi <Pawan.Badganchi@kpit.com> 12Signed-off-by: Mingli Yu <mingli.yu@windriver.com> 13--- 14 include/curl/curl.h | 1 + 15 lib/hsts.c | 15 +++++++++ 16 lib/hsts.h | 2 ++ 17 lib/setopt.c | 48 ++++++++++++++++++++++++----- 18 lib/share.c | 32 +++++++++++++++++-- 19 lib/share.h | 6 +++- 20 lib/transfer.c | 3 ++ 21 lib/url.c | 6 +++- 22 lib/urldata.h | 2 ++ 23 9 files changed, 109 insertions(+), 11 deletions(-) 24 25--- a/include/curl/curl.h 26+++ b/include/curl/curl.h 27@@ -2953,6 +2953,7 @@ typedef enum { 28 CURL_LOCK_DATA_SSL_SESSION, 29 CURL_LOCK_DATA_CONNECT, 30 CURL_LOCK_DATA_PSL, 31+ CURL_LOCK_DATA_HSTS, 32 CURL_LOCK_DATA_LAST 33 } curl_lock_data; 34 35--- a/lib/hsts.c 36+++ b/lib/hsts.c 37@@ -37,6 +37,7 @@ 38 #include "parsedate.h" 39 #include "rand.h" 40 #include "rename.h" 41+#include "share.h" 42 #include "strtoofft.h" 43 44 /* The last 3 #include files should be in this order */ 45@@ -561,4 +562,18 @@ 46 return CURLE_OK; 47 } 48 49+void Curl_hsts_loadfiles(struct Curl_easy *data) 50+{ 51+ struct curl_slist *l = data->set.hstslist; 52+ if(l) { 53+ Curl_share_lock(data, CURL_LOCK_DATA_HSTS, CURL_LOCK_ACCESS_SINGLE); 54+ 55+ while(l) { 56+ (void)Curl_hsts_loadfile(data, data->hsts, l->data); 57+ l = l->next; 58+ } 59+ Curl_share_unlock(data, CURL_LOCK_DATA_HSTS); 60+ } 61+} 62+ 63 #endif /* CURL_DISABLE_HTTP || CURL_DISABLE_HSTS */ 64--- a/lib/hsts.h 65+++ b/lib/hsts.h 66@@ -59,9 +59,11 @@ CURLcode Curl_hsts_loadfile(struct Curl_ 67 struct hsts *h, const char *file); 68 CURLcode Curl_hsts_loadcb(struct Curl_easy *data, 69 struct hsts *h); 70+void Curl_hsts_loadfiles(struct Curl_easy *data); 71 #else 72 #define Curl_hsts_cleanup(x) 73 #define Curl_hsts_loadcb(x,y) CURLE_OK 74 #define Curl_hsts_save(x,y,z) 75+#define Curl_hsts_loadfiles(x) 76 #endif /* CURL_DISABLE_HTTP || CURL_DISABLE_HSTS */ 77 #endif /* HEADER_CURL_HSTS_H */ 78--- a/lib/setopt.c 79+++ b/lib/setopt.c 80@@ -2260,9 +2260,14 @@ CURLcode Curl_vsetopt(struct Curl_easy * 81 data->cookies = NULL; 82 #endif 83 84+#ifndef CURL_DISABLE_HSTS 85+ if(data->share->hsts == data->hsts) 86+ data->hsts = NULL; 87+#endif 88+#ifdef USE_SSL 89 if(data->share->sslsession == data->state.session) 90 data->state.session = NULL; 91- 92+#endif 93 #ifdef USE_LIBPSL 94 if(data->psl == &data->share->psl) 95 data->psl = data->multi? &data->multi->psl: NULL; 96@@ -2296,10 +2301,19 @@ CURLcode Curl_vsetopt(struct Curl_easy * 97 data->cookies = data->share->cookies; 98 } 99 #endif /* CURL_DISABLE_HTTP */ 100+#ifndef CURL_DISABLE_HSTS 101+ if(data->share->hsts) { 102+ /* first free the private one if any */ 103+ Curl_hsts_cleanup(&data->hsts); 104+ data->hsts = data->share->hsts; 105+ } 106+#endif /* CURL_DISABLE_HTTP */ 107+#ifdef USE_SSL 108 if(data->share->sslsession) { 109 data->set.general_ssl.max_ssl_sessions = data->share->max_ssl_sessions; 110 data->state.session = data->share->sslsession; 111 } 112+#endif 113 #ifdef USE_LIBPSL 114 if(data->share->specifier & (1 << CURL_LOCK_DATA_PSL)) 115 data->psl = &data->share->psl; 116@@ -3049,19 +3063,39 @@ CURLcode Curl_vsetopt(struct Curl_easy * 117 case CURLOPT_HSTSWRITEDATA: 118 data->set.hsts_write_userp = va_arg(param, void *); 119 break; 120- case CURLOPT_HSTS: 121+ case CURLOPT_HSTS: { 122+ struct curl_slist *h; 123 if(!data->hsts) { 124 data->hsts = Curl_hsts_init(); 125 if(!data->hsts) 126 return CURLE_OUT_OF_MEMORY; 127 } 128 argptr = va_arg(param, char *); 129- result = Curl_setstropt(&data->set.str[STRING_HSTS], argptr); 130- if(result) 131- return result; 132- if(argptr) 133- (void)Curl_hsts_loadfile(data, data->hsts, argptr); 134+ if(argptr) { 135+ result = Curl_setstropt(&data->set.str[STRING_HSTS], argptr); 136+ if(result) 137+ return result; 138+ /* this needs to build a list of file names to read from, so that it can 139+ read them later, as we might get a shared HSTS handle to load them 140+ into */ 141+ h = curl_slist_append(data->set.hstslist, argptr); 142+ if(!h) { 143+ curl_slist_free_all(data->set.hstslist); 144+ data->set.hstslist = NULL; 145+ return CURLE_OUT_OF_MEMORY; 146+ } 147+ data->set.hstslist = h; /* store the list for later use */ 148+ } 149+ else { 150+ /* clear the list of HSTS files */ 151+ curl_slist_free_all(data->set.hstslist); 152+ data->set.hstslist = NULL; 153+ if(!data->share || !data->share->hsts) 154+ /* throw away the HSTS cache unless shared */ 155+ Curl_hsts_cleanup(&data->hsts); 156+ } 157 break; 158+ } 159 case CURLOPT_HSTS_CTRL: 160 arg = va_arg(param, long); 161 if(arg & CURLHSTS_ENABLE) { 162--- a/lib/share.c 163+++ b/lib/share.c 164@@ -29,9 +29,11 @@ 165 #include "share.h" 166 #include "psl.h" 167 #include "vtls/vtls.h" 168-#include "curl_memory.h" 169+#include "hsts.h" 170 171-/* The last #include file should be: */ 172+/* The last 3 #include files should be in this order */ 173+#include "curl_printf.h" 174+#include "curl_memory.h" 175 #include "memdebug.h" 176 177 struct Curl_share * 178@@ -89,6 +91,18 @@ curl_share_setopt(struct Curl_share *sha 179 #endif 180 break; 181 182+ case CURL_LOCK_DATA_HSTS: 183+#ifndef CURL_DISABLE_HSTS 184+ if(!share->hsts) { 185+ share->hsts = Curl_hsts_init(); 186+ if(!share->hsts) 187+ res = CURLSHE_NOMEM; 188+ } 189+#else /* CURL_DISABLE_HSTS */ 190+ res = CURLSHE_NOT_BUILT_IN; 191+#endif 192+ break; 193+ 194 case CURL_LOCK_DATA_SSL_SESSION: 195 #ifdef USE_SSL 196 if(!share->sslsession) { 197@@ -141,6 +155,16 @@ curl_share_setopt(struct Curl_share *sha 198 #endif 199 break; 200 201+ case CURL_LOCK_DATA_HSTS: 202+#ifndef CURL_DISABLE_HSTS 203+ if(share->hsts) { 204+ Curl_hsts_cleanup(&share->hsts); 205+ } 206+#else /* CURL_DISABLE_HSTS */ 207+ res = CURLSHE_NOT_BUILT_IN; 208+#endif 209+ break; 210+ 211 case CURL_LOCK_DATA_SSL_SESSION: 212 #ifdef USE_SSL 213 Curl_safefree(share->sslsession); 214@@ -207,6 +231,10 @@ curl_share_cleanup(struct Curl_share *sh 215 Curl_cookie_cleanup(share->cookies); 216 #endif 217 218+#ifndef CURL_DISABLE_HSTS 219+ Curl_hsts_cleanup(&share->hsts); 220+#endif 221+ 222 #ifdef USE_SSL 223 if(share->sslsession) { 224 size_t i; 225--- a/lib/share.h 226+++ b/lib/share.h 227@@ -59,10 +59,14 @@ struct Curl_share { 228 #ifdef USE_LIBPSL 229 struct PslCache psl; 230 #endif 231- 232+#ifndef CURL_DISABLE_HSTS 233+ struct hsts *hsts; 234+#endif 235+#ifdef USE_SSL 236 struct Curl_ssl_session *sslsession; 237 size_t max_ssl_sessions; 238 long sessionage; 239+#endif 240 }; 241 242 CURLSHcode Curl_share_lock(struct Curl_easy *, curl_lock_data, 243--- a/lib/transfer.c 244+++ b/lib/transfer.c 245@@ -1398,6 +1398,9 @@ CURLcode Curl_pretransfer(struct Curl_ea 246 if(data->state.resolve) 247 result = Curl_loadhostpairs(data); 248 249+ /* If there is a list of hsts files to read */ 250+ Curl_hsts_loadfiles(data); 251+ 252 if(!result) { 253 /* Allow data->set.use_port to set which port to use. This needs to be 254 * disabled for example when we follow Location: headers to URLs using 255--- a/lib/url.c 256+++ b/lib/url.c 257@@ -434,7 +434,11 @@ CURLcode Curl_close(struct Curl_easy **d 258 Curl_altsvc_save(data, data->asi, data->set.str[STRING_ALTSVC]); 259 Curl_altsvc_cleanup(&data->asi); 260 Curl_hsts_save(data, data->hsts, data->set.str[STRING_HSTS]); 261- Curl_hsts_cleanup(&data->hsts); 262+#ifndef CURL_DISABLE_HSTS 263+ if(!data->share || !data->share->hsts) 264+ Curl_hsts_cleanup(&data->hsts); 265+ curl_slist_free_all(data->set.hstslist); /* clean up list */ 266+#endif 267 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH) 268 Curl_http_auth_cleanup_digest(data); 269 #endif 270--- a/lib/urldata.h 271+++ b/lib/urldata.h 272@@ -1670,6 +1670,8 @@ 273 274 void *seek_client; /* pointer to pass to the seek callback */ 275 #ifndef CURL_DISABLE_HSTS 276+ struct curl_slist *hstslist; /* list of HSTS files set by 277+ curl_easy_setopt(HSTS) calls */ 278 curl_hstsread_callback hsts_read; 279 void *hsts_read_userp; 280 curl_hstswrite_callback hsts_write; 281