diff --git a/0004-curl-7.51.0-CVE-2016-9586.patch b/0004-curl-7.51.0-CVE-2016-9586.patch new file mode 100644 index 0000000..0f5683d --- /dev/null +++ b/0004-curl-7.51.0-CVE-2016-9586.patch @@ -0,0 +1,283 @@ +From 7ad1cdfb256f7e1b84fc960a8ca1403cca5d930f Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Tue, 8 Nov 2016 15:30:33 +0100 +Subject: [PATCH 1/2] printf: fix ".*f" handling + +It would always use precision 1 instead of reading it from the argument +list as intended. + +Reported-by: Ray Satiro + +Bug: #1113 + +Upstream-commit: 5dd1b65f79bc6dc75b752c53f3fa853b2a3b6d69 +Signed-off-by: Kamil Dudka +--- + lib/mprintf.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/lib/mprintf.c b/lib/mprintf.c +index 2c88aa8..e1ad537 100644 +--- a/lib/mprintf.c ++++ b/lib/mprintf.c +@@ -303,7 +303,6 @@ static int dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos, + flags |= FLAGS_ALT; + break; + case '.': +- flags |= FLAGS_PREC; + if('*' == *fmt) { + /* The precision is picked from a specified parameter */ + +-- +2.7.4 + + +From 3162df571802b2c94d9969b6b269cd0d50c6650d Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Tue, 8 Nov 2016 15:32:37 +0100 +Subject: [PATCH 2/2] printf: fix floating point buffer overflow issues + +... and add a bunch of floating point printf tests + +Upstream-commit: 3ab3c16db6a5674f53cf23d56512a405fde0b2c9 +Signed-off-by: Kamil Dudka +--- + lib/mprintf.c | 20 +++++++- + tests/data/test557 | 1 + + tests/libtest/lib557.c | 136 +++++++++++++++++++++++++++++++++++++++++++++++-- + 3 files changed, 152 insertions(+), 5 deletions(-) + +diff --git a/lib/mprintf.c b/lib/mprintf.c +index e1ad537..e3a690b 100644 +--- a/lib/mprintf.c ++++ b/lib/mprintf.c +@@ -92,7 +92,8 @@ + # define mp_uintmax_t unsigned long + #endif + +-#define BUFFSIZE 256 /* buffer for long-to-str and float-to-str calcs */ ++#define BUFFSIZE 326 /* buffer for long-to-str and float-to-str calcs, should ++ fit negative DBL_MAX (317 letters) */ + #define MAX_PARAMETERS 128 /* lame static limit */ + + #ifdef __AMIGA__ +@@ -916,12 +917,25 @@ static int dprintf_formatf( + *fptr = 0; + + if(width >= 0) { ++ if(width >= (long)sizeof(work)) ++ width = sizeof(work)-1; + /* RECURSIVE USAGE */ + len = curl_msnprintf(fptr, left, "%ld", width); + fptr += len; + left -= len; + } + if(prec >= 0) { ++ /* for each digit in the integer part, we can have one less ++ precision */ ++ size_t maxprec = sizeof(work) - 2; ++ double val = p->data.dnum; ++ while(val >= 10.0) { ++ val /= 10; ++ maxprec--; ++ } ++ ++ if(prec > (long)maxprec) ++ prec = maxprec-1; + /* RECURSIVE USAGE */ + len = curl_msnprintf(fptr, left, ".%ld", prec); + fptr += len; +@@ -941,7 +955,9 @@ static int dprintf_formatf( + /* NOTE NOTE NOTE!! Not all sprintf implementations return number of + output characters */ + (sprintf)(work, formatbuf, p->data.dnum); +- ++#ifdef CURLDEBUG ++ assert(strlen(work) <= sizeof(work)); ++#endif + for(fptr=work; *fptr; fptr++) + OUTCHAR(*fptr); + } +diff --git a/tests/data/test557 b/tests/data/test557 +index 8d0944a..ad9350f 100644 +--- a/tests/data/test557 ++++ b/tests/data/test557 +@@ -40,6 +40,7 @@ All curl_mprintf() unsigned long tests OK! + All curl_mprintf() signed long tests OK! + All curl_mprintf() curl_off_t tests OK! + All curl_mprintf() strings tests OK! ++All float strings tests OK! + + + +diff --git a/tests/libtest/lib557.c b/tests/libtest/lib557.c +index 683ca08..8c62a0e 100644 +--- a/tests/libtest/lib557.c ++++ b/tests/libtest/lib557.c +@@ -1374,16 +1374,31 @@ static int test_curl_off_t_formatting(void) + return failed; + } + +-static int string_check(char *buf, const char *buf2) ++static int _string_check(int linenumber, char *buf, const char *buf2) + { + if(strcmp(buf, buf2)) { + /* they shouldn't differ */ +- printf("sprintf failed:\nwe '%s'\nsystem: '%s'\n", +- buf, buf2); ++ printf("sprintf line %d failed:\nwe '%s'\nsystem: '%s'\n", ++ linenumber, buf, buf2); + return 1; + } + return 0; + } ++#define string_check(x,y) _string_check(__LINE__, x, y) ++ ++static int _strlen_check(int linenumber, char *buf, size_t len) ++{ ++ size_t buflen = strlen(buf); ++ if(len != buflen) { ++ /* they shouldn't differ */ ++ printf("sprintf strlen:%d failed:\nwe '%d'\nsystem: '%d'\n", ++ linenumber, buflen, len); ++ return 1; ++ } ++ return 0; ++} ++ ++#define strlen_check(x,y) _strlen_check(__LINE__, x, y) + + /* + * The output strings in this test need to have been verified with a system +@@ -1523,6 +1538,119 @@ static int test_weird_arguments(void) + return errors; + } + ++/* DBL_MAX value from Linux */ ++#define MAXIMIZE -179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.000000 ++ ++static int test_float_formatting(void) ++{ ++ int errors = 0; ++ char buf[512]; /* larger than max float size */ ++ curl_msnprintf(buf, sizeof(buf), "%f", 9.0); ++ errors += string_check(buf, "9.000000"); ++ ++ curl_msnprintf(buf, sizeof(buf), "%.1f", 9.1); ++ errors += string_check(buf, "9.1"); ++ ++ curl_msnprintf(buf, sizeof(buf), "%.2f", 9.1); ++ errors += string_check(buf, "9.10"); ++ ++ curl_msnprintf(buf, sizeof(buf), "%.0f", 9.1); ++ errors += string_check(buf, "9"); ++ ++ curl_msnprintf(buf, sizeof(buf), "%0f", 9.1); ++ errors += string_check(buf, "9.100000"); ++ ++ curl_msnprintf(buf, sizeof(buf), "%10f", 9.1); ++ errors += string_check(buf, " 9.100000"); ++ ++ curl_msnprintf(buf, sizeof(buf), "%10.3f", 9.1); ++ errors += string_check(buf, " 9.100"); ++ ++ curl_msnprintf(buf, sizeof(buf), "%-10.3f", 9.1); ++ errors += string_check(buf, "9.100 "); ++ ++ curl_msnprintf(buf, sizeof(buf), "%-10.3f", 9.123456); ++ errors += string_check(buf, "9.123 "); ++ ++ curl_msnprintf(buf, sizeof(buf), "%.-2f", 9.1); ++ errors += string_check(buf, "9.100000"); ++ ++ curl_msnprintf(buf, sizeof(buf), "%*f", 10, 9.1); ++ errors += string_check(buf, " 9.100000"); ++ ++ curl_msnprintf(buf, sizeof(buf), "%*f", 3, 9.1); ++ errors += string_check(buf, "9.100000"); ++ ++ curl_msnprintf(buf, sizeof(buf), "%*f", 6, 9.2987654); ++ errors += string_check(buf, "9.298765"); ++ ++ curl_msnprintf(buf, sizeof(buf), "%*f", 6, 9.298765); ++ errors += string_check(buf, "9.298765"); ++ ++ curl_msnprintf(buf, sizeof(buf), "%*f", 6, 9.29876); ++ errors += string_check(buf, "9.298760"); ++ ++ curl_msnprintf(buf, sizeof(buf), "%.*f", 6, 9.2987654); ++ errors += string_check(buf, "9.298765"); ++ curl_msnprintf(buf, sizeof(buf), "%.*f", 5, 9.2987654); ++ errors += string_check(buf, "9.29877"); ++ curl_msnprintf(buf, sizeof(buf), "%.*f", 4, 9.2987654); ++ errors += string_check(buf, "9.2988"); ++ curl_msnprintf(buf, sizeof(buf), "%.*f", 3, 9.2987654); ++ errors += string_check(buf, "9.299"); ++ curl_msnprintf(buf, sizeof(buf), "%.*f", 2, 9.2987654); ++ errors += string_check(buf, "9.30"); ++ curl_msnprintf(buf, sizeof(buf), "%.*f", 1, 9.2987654); ++ errors += string_check(buf, "9.3"); ++ curl_msnprintf(buf, sizeof(buf), "%.*f", 0, 9.2987654); ++ errors += string_check(buf, "9"); ++ ++ /* very large precisions easily turn into system specific outputs so we only ++ check the output buffer length here as we know the internal limit */ ++ ++ curl_msnprintf(buf, sizeof(buf), "%.*f", (1<<30), 9.2987654); ++ errors += strlen_check(buf, 325); ++ ++ curl_msnprintf(buf, sizeof(buf), "%10000.10000f", 9.2987654); ++ errors += strlen_check(buf, 325); ++ ++ curl_msnprintf(buf, sizeof(buf), "%240.10000f", ++ 123456789123456789123456789.2987654); ++ errors += strlen_check(buf, 325); ++ ++ /* 1<<31 turns negative (-2147483648) when used signed */ ++ curl_msnprintf(buf, sizeof(buf), "%*f", (1<<31), 9.1); ++ errors += string_check(buf, "9.100000"); ++ ++ /* curl_msnprintf() limits a single float output to 325 bytes maximum ++ width */ ++ curl_msnprintf(buf, sizeof(buf), "%*f", (1<<30), 9.1); ++ errors += string_check(buf, " 9.100000"); ++ curl_msnprintf(buf, sizeof(buf), "%100000f", 9.1); ++ errors += string_check(buf, " 9.100000"); ++ ++ curl_msnprintf(buf, sizeof(buf), "%f", MAXIMIZE); ++ errors += strlen_check(buf, 317); ++ ++ curl_msnprintf(buf, 2, "%f", MAXIMIZE); ++ errors += strlen_check(buf, 1); ++ curl_msnprintf(buf, 3, "%f", MAXIMIZE); ++ errors += strlen_check(buf, 2); ++ curl_msnprintf(buf, 4, "%f", MAXIMIZE); ++ errors += strlen_check(buf, 3); ++ curl_msnprintf(buf, 5, "%f", MAXIMIZE); ++ errors += strlen_check(buf, 4); ++ curl_msnprintf(buf, 6, "%f", MAXIMIZE); ++ errors += strlen_check(buf, 5); ++ ++ if(!errors) ++ printf("All float strings tests OK!\n"); ++ else ++ printf("test_float_formatting Failed!\n"); ++ ++ return errors; ++} ++ + + int test(char *URL) + { +@@ -1547,6 +1675,8 @@ int test(char *URL) + + errors += test_string_formatting(); + ++ errors += test_float_formatting(); ++ + if(errors) + return TEST_ERR_MAJOR_BAD; + else +-- +2.7.4 + diff --git a/curl.spec b/curl.spec index d80dffd..b23f302 100644 --- a/curl.spec +++ b/curl.spec @@ -1,7 +1,7 @@ Summary: A utility for getting files from remote servers (FTP, HTTP, and others) Name: curl Version: 7.51.0 -Release: 3%{?dist} +Release: 4%{?dist} License: MIT Group: Applications/Internet Source: http://curl.haxx.se/download/%{name}-%{version}.tar.lzma @@ -15,6 +15,9 @@ Patch2: 0002-curl-7.51.0-file-host.patch # map CURL_SSLVERSION_DEFAULT to NSS default, add support for TLS 1.3 (#1396719) Patch3: 0003-curl-7.51.0-tls-version.patch +# fix floating point buffer overflow issues (CVE-2016-9586) +Patch4: 0004-curl-7.51.0-CVE-2016-9586.patch + # patch making libcurl multilib ready Patch101: 0101-curl-7.32.0-multilib.patch @@ -134,6 +137,7 @@ documentation of the library, too. %patch1 -p1 %patch2 -p1 %patch3 -p1 +%patch4 -p1 # Fedora patches %patch101 -p1 @@ -241,6 +245,9 @@ rm -rf $RPM_BUILD_ROOT %{_datadir}/aclocal/libcurl.m4 %changelog +* Fri Dec 23 2016 Kamil Dudka 7.51.0-4 +- fix floating point buffer overflow issues (CVE-2016-9586) + * Mon Nov 21 2016 Kamil Dudka 7.51.0-3 - map CURL_SSLVERSION_DEFAULT to NSS default, add support for TLS 1.3 (#1396719)