From 3696fc1ba79d9b34660c44150be5e93ecf87dd9e Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 17 Oct 2014 12:59:32 +0200 Subject: [PATCH] curl_easy_duphandle: CURLOPT_COPYPOSTFIELDS read out of bounds When duplicating a handle, the data to post was duplicated using strdup() when it could be binary and contain zeroes and it was not even zero terminated! This caused read out of bounds crashes/segfaults. Since the lib/strdup.c file no longer is easily shared with the curl tool with this change, it now uses its own version instead. Bug: http://curl.haxx.se/docs/adv_20141105.html CVE: CVE-2014-3707 Reported-By: Symeon Paraschoudis --- lib/formdata.c | 52 +++++++++------------------------------------------- lib/strdup.c | 32 +++++++++++++++++++++++++++----- lib/strdup.h | 3 ++- lib/url.c | 22 +++++++++++++++++----- lib/urldata.h | 11 +++++++++-- src/Makefile.inc | 4 ++-- src/tool_setup.h | 5 ++--- src/tool_strdup.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ src/tool_strdup.h | 30 ++++++++++++++++++++++++++++++ 9 files changed, 145 insertions(+), 61 deletions(-) create mode 100644 src/tool_strdup.c create mode 100644 src/tool_strdup.h Index: curl-7.37.1/lib/formdata.c =================================================================== --- curl-7.37.1.orig/lib/formdata.c +++ curl-7.37.1/lib/formdata.c @@ -36,6 +36,7 @@ #include "strequal.h" #include "curl_memory.h" #include "sendf.h" +#include "strdup.h" #define _MPRINTF_REPLACE /* use our functions only */ #include @@ -214,46 +215,6 @@ static const char *ContentTypeForFilenam /*************************************************************************** * - * memdup() - * - * Copies the 'source' data to a newly allocated buffer buffer (that is - * returned). Uses buffer_length if not null, else uses strlen to determine - * the length of the buffer to be copied - * - * Returns the new pointer or NULL on failure. - * - ***************************************************************************/ -static char *memdup(const char *src, size_t buffer_length) -{ - size_t length; - bool add = FALSE; - char *buffer; - - if(buffer_length) - length = buffer_length; - else if(src) { - length = strlen(src); - add = TRUE; - } - else - /* no length and a NULL src pointer! */ - return strdup(""); - - buffer = malloc(length+add); - if(!buffer) - return NULL; /* fail */ - - memcpy(buffer, src, length); - - /* if length unknown do null termination */ - if(add) - buffer[length] = '\0'; - - return buffer; -} - -/*************************************************************************** - * * FormAdd() * * Stores a formpost parameter and builds the appropriate linked list. @@ -682,9 +643,12 @@ CURLFORMcode FormAdd(struct curl_httppos (form == first_form) ) { /* Note that there's small risk that form->name is NULL here if the app passed in a bad combo, so we better check for that first. */ - if(form->name) + if(form->name) { /* copy name (without strdup; possibly contains null characters) */ - form->name = memdup(form->name, form->namelength); + form->name = Curl_memdup(form->name, form->namelength? + form->namelength: + strlen(form->name)+1); + } if(!form->name) { return_value = CURL_FORMADD_MEMORY; break; @@ -695,7 +659,7 @@ CURLFORMcode FormAdd(struct curl_httppos HTTPPOST_PTRCONTENTS | HTTPPOST_PTRBUFFER | HTTPPOST_CALLBACK)) ) { /* copy value (without strdup; possibly contains null characters) */ - form->value = memdup(form->value, form->contentslength); + form->value = Curl_memdup(form->value, form->contentslength); if(!form->value) { return_value = CURL_FORMADD_MEMORY; break; Index: curl-7.37.1/lib/strdup.c =================================================================== --- curl-7.37.1.orig/lib/strdup.c +++ curl-7.37.1/lib/strdup.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -19,12 +19,12 @@ * KIND, either express or implied. * ***************************************************************************/ -/* - * This file is 'mem-include-scan' clean. See test 1132. - */ #include "curl_setup.h" - #include "strdup.h" +#include "curl_memory.h" + +/* The last #include file should be: */ +#include "memdebug.h" #ifndef HAVE_STRDUP char *curlx_strdup(const char *str) @@ -50,3 +50,25 @@ char *curlx_strdup(const char *str) } #endif + +/*************************************************************************** + * + * Curl_memdup(source, length) + * + * Copies the 'source' data to a newly allocated buffer (that is + * returned). Copies 'length' bytes. + * + * Returns the new pointer or NULL on failure. + * + ***************************************************************************/ +char *Curl_memdup(const char *src, size_t length) +{ + char *buffer = malloc(length); + if(!buffer) + return NULL; /* fail */ + + memcpy(buffer, src, length); + + /* if length unknown do null termination */ + return buffer; +} Index: curl-7.37.1/lib/strdup.h =================================================================== --- curl-7.37.1.orig/lib/strdup.h +++ curl-7.37.1/lib/strdup.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -26,5 +26,6 @@ #ifndef HAVE_STRDUP extern char *curlx_strdup(const char *str); #endif +char *Curl_memdup(const char *src, size_t buffer_length); #endif /* HEADER_CURL_STRDUP_H */ Index: curl-7.37.1/lib/url.c =================================================================== --- curl-7.37.1.orig/lib/url.c +++ curl-7.37.1/lib/url.c @@ -125,6 +125,7 @@ int curl_win32_idn_to_ascii(const char * #include "multihandle.h" #include "pipeline.h" #include "dotdot.h" +#include "strdup.h" #define _MPRINTF_REPLACE /* use our functions only */ #include @@ -270,8 +271,9 @@ void Curl_freeset(struct SessionHandle * { /* Free all dynamic strings stored in the data->set substructure. */ enum dupstring i; - for(i=(enum dupstring)0; i < STRING_LAST; i++) + for(i=(enum dupstring)0; i < STRING_LAST; i++) { Curl_safefree(data->set.str[i]); + } if(data->change.referer_alloc) { Curl_safefree(data->change.referer); @@ -356,14 +358,24 @@ CURLcode Curl_dupset(struct SessionHandl memset(dst->set.str, 0, STRING_LAST * sizeof(char *)); /* duplicate all strings */ - for(i=(enum dupstring)0; i< STRING_LAST; i++) { + for(i=(enum dupstring)0; i< STRING_LASTZEROTERMINATED; i++) { r = setstropt(&dst->set.str[i], src->set.str[i]); if(r != CURLE_OK) - break; + return r; } - /* If a failure occurred, freeing has to be performed externally. */ - return r; + /* duplicate memory areas pointed to */ + i = STRING_COPYPOSTFIELDS; + if(src->set.postfieldsize && src->set.str[i]) { + /* postfieldsize is curl_off_t, Curl_memdup() takes a size_t ... */ + dst->set.str[i] = Curl_memdup(src->set.str[i], src->set.postfieldsize); + if(!dst->set.str[i]) + return CURLE_OUT_OF_MEMORY; + /* point to the new copy */ + dst->set.postfields = dst->set.str[i]; + } + + return CURLE_OK; } /* Index: curl-7.37.1/lib/urldata.h =================================================================== --- curl-7.37.1.orig/lib/urldata.h +++ curl-7.37.1/lib/urldata.h @@ -1359,7 +1359,6 @@ enum dupstring { STRING_KRB_LEVEL, /* krb security level */ STRING_NETRC_FILE, /* if not NULL, use this instead of trying to find $HOME/.netrc */ - STRING_COPYPOSTFIELDS, /* if POST, set the fields' values here */ STRING_PROXY, /* proxy to use */ STRING_SET_RANGE, /* range, if used */ STRING_SET_REFERER, /* custom string for the HTTP referer field */ @@ -1401,7 +1400,15 @@ enum dupstring { STRING_BEARER, /* , if used */ - /* -- end of strings -- */ + /* -- end of zero-terminated strings -- */ + + STRING_LASTZEROTERMINATED, + + /* -- below this are pointers to binary data that cannot be strdup'ed. + Each such pointer must be added manually to Curl_dupset() --- */ + + STRING_COPYPOSTFIELDS, /* if POST, set the fields' values here */ + STRING_LAST /* not used, just an end-of-list marker */ }; Index: curl-7.37.1/src/Makefile.inc =================================================================== --- curl-7.37.1.orig/src/Makefile.inc +++ curl-7.37.1/src/Makefile.inc @@ -11,7 +11,6 @@ # the official API, but we re-use the code here to avoid duplication. CURLX_CFILES = \ ../lib/strtoofft.c \ - ../lib/strdup.c \ ../lib/rawstr.c \ ../lib/nonblock.c \ ../lib/warnless.c @@ -19,7 +18,6 @@ CURLX_CFILES = \ CURLX_HFILES = \ ../lib/curl_setup.h \ ../lib/strtoofft.h \ - ../lib/strdup.h \ ../lib/rawstr.h \ ../lib/nonblock.h \ ../lib/warnless.h @@ -55,6 +53,7 @@ CURL_CFILES = \ tool_panykey.c \ tool_paramhlp.c \ tool_parsecfg.c \ + tool_strdup.c \ tool_setopt.c \ tool_sleep.c \ tool_urlglob.c \ @@ -99,6 +98,7 @@ CURL_HFILES = \ tool_setopt.h \ tool_setup.h \ tool_sleep.h \ + tool_strdup.h \ tool_urlglob.h \ tool_util.h \ tool_version.h \ Index: curl-7.37.1/src/tool_setup.h =================================================================== --- curl-7.37.1.orig/src/tool_setup.h +++ curl-7.37.1/src/tool_setup.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -67,8 +67,7 @@ #endif #ifndef HAVE_STRDUP -# include "strdup.h" -# define strdup(ptr) curlx_strdup(ptr) +# include "tool_strdup.h" #endif #endif /* HEADER_CURL_TOOL_SETUP_H */ Index: curl-7.37.1/src/tool_strdup.c =================================================================== --- /dev/null +++ curl-7.37.1/src/tool_strdup.c @@ -0,0 +1,47 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +#include "strdup.h" + +#ifndef HAVE_STRDUP +char *strdup(const char *str) +{ + size_t len; + char *newstr; + + if(!str) + return (char *)NULL; + + len = strlen(str); + + if(len >= ((size_t)-1) / sizeof(char)) + return (char *)NULL; + + newstr = malloc((len+1)*sizeof(char)); + if(!newstr) + return (char *)NULL; + + memcpy(newstr,str,(len+1)*sizeof(char)); + + return newstr; + +} +#endif Index: curl-7.37.1/src/tool_strdup.h =================================================================== --- /dev/null +++ curl-7.37.1/src/tool_strdup.h @@ -0,0 +1,30 @@ +#ifndef HEADER_TOOL_STRDUP_H +#define HEADER_TOOL_STRDUP_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +#include "tool_setup.h" + +#ifndef HAVE_STRDUP +extern char *strdup(const char *str); +#endif + +#endif /* HEADER_TOOL_STRDUP_H */