From 7c8322243bf4fe57a7f5d042182c1b5c541bdaeb Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Mon, 2 Jul 2007 00:56:18 +0000 Subject: [PATCH] Avoid address wraparound inside system functions. --- ChangeLog | 8 ++++++++ lib/sprintf.c | 15 ++++++++++++--- lib/vsprintf.c | 13 +++++++++++-- modules/sprintf-posix | 1 + modules/vsprintf-posix | 1 + 5 files changed, 33 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index d84ab3537..dc954fb67 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2007-07-01 Bruno Haible + + * lib/sprintf.c (sprintf): Limit the available length estimation, + to avoid address wraparound. + * lib/vsprintf.c (vsprintf): Likewise. + * modules/sprintf-posix (Dependencies): Add stdint. + * modules/vsprintf-posix (Dependencies): Likewise. + 2007-07-01 Bruno Haible * gnulib-tool (self_abspathname): Determine PATH_SEPARATOR and handle diff --git a/lib/sprintf.c b/lib/sprintf.c index ab14107da..035fe2137 100644 --- a/lib/sprintf.c +++ b/lib/sprintf.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include "vasnprintf.h" @@ -46,11 +47,19 @@ sprintf (char *str, const char *format, ...) { char *output; size_t len; - /* vasnprintf fails with EOVERFLOW when the buffer size argument is larger - than INT_MAX (if that fits into a 'size_t' at all). */ - size_t lenbuf = (SIZE_MAX < INT_MAX ? SIZE_MAX : INT_MAX); + size_t lenbuf; va_list args; + /* vasnprintf fails with EOVERFLOW when the buffer size argument is larger + than INT_MAX (if that fits into a 'size_t' at all). + Also note that glibc's iconv fails with E2BIG when we pass a length that + is so large that str + lenbuf wraps around, i.e. + (uintptr_t) (str + lenbuf) < (uintptr_t) str. + Therefore set lenbuf = min (SIZE_MAX, INT_MAX, - (uintptr_t) str - 1). */ + lenbuf = (SIZE_MAX < INT_MAX ? SIZE_MAX : INT_MAX); + if (lenbuf > ~ (uintptr_t) str) + lenbuf = ~ (uintptr_t) str; + va_start (args, format); output = vasnprintf (str, &lenbuf, format, args); len = lenbuf; diff --git a/lib/vsprintf.c b/lib/vsprintf.c index a9d840d9c..88e528db3 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include "vasnprintf.h" @@ -46,9 +47,17 @@ vsprintf (char *str, const char *format, va_list args) { char *output; size_t len; + size_t lenbuf; + /* vasnprintf fails with EOVERFLOW when the buffer size argument is larger - than INT_MAX (if that fits into a 'size_t' at all). */ - size_t lenbuf = (SIZE_MAX < INT_MAX ? SIZE_MAX : INT_MAX); + than INT_MAX (if that fits into a 'size_t' at all). + Also note that glibc's iconv fails with E2BIG when we pass a length that + is so large that str + lenbuf wraps around, i.e. + (uintptr_t) (str + lenbuf) < (uintptr_t) str. + Therefore set lenbuf = min (SIZE_MAX, INT_MAX, - (uintptr_t) str - 1). */ + lenbuf = (SIZE_MAX < INT_MAX ? SIZE_MAX : INT_MAX); + if (lenbuf > ~ (uintptr_t) str) + lenbuf = ~ (uintptr_t) str; output = vasnprintf (str, &lenbuf, format, args); len = lenbuf; diff --git a/modules/sprintf-posix b/modules/sprintf-posix index 7bfa94b23..0ae1ef443 100644 --- a/modules/sprintf-posix +++ b/modules/sprintf-posix @@ -17,6 +17,7 @@ printf-frexpl signbit fpucw printf-safe +stdint configure.ac: gl_FUNC_SPRINTF_POSIX diff --git a/modules/vsprintf-posix b/modules/vsprintf-posix index ba79781a2..d96745cfc 100644 --- a/modules/vsprintf-posix +++ b/modules/vsprintf-posix @@ -17,6 +17,7 @@ printf-frexpl signbit fpucw printf-safe +stdint configure.ac: gl_FUNC_VSPRINTF_POSIX -- 2.11.0