From 7d5fdf0743886e6d479b9a24d22e02bcb3aa82a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Fri, 2 Oct 2020 22:32:36 +0200 Subject: [PATCH] miniupnpc: Fix usage of Windows _snprintf() function _snprintf() differs from snprintf() in: * on overflow it returns -1 instead of required buffer size * on overflow it does not fill nul byte * does not accept NULL/0 as a buffer Microsoft implemented snprintf() in Visual Studio 2015 as part of UCRT. Mingw32 contains snprintf() implementation only when __USE_MINGW_ANSI_STDIO is defined. Mingw-w64 versions prior to 8.0.0. contain snprintf() implementation when __USE_MINGW_ANSI_STDIO or _UCRT is defined. Since version 8.0.0 it is always supported. Mingw-w64 defines both __MINGW32__ and __MINGW64_VERSION_MAJOR macros. Mingw32 defines only __MINGW32__. _scprintf() just count number of bytes needed for formatting string, so it is basically return value of snprintf(). This change updates miniupnpc code to use snprintf() when is provided by compiler/runtime to avoid usage _snprintf(). And also this changes updates miniupnpc emulation of snprintf() by _snprintf() and _scprintf() functions to avoid buffer overflows. For inspiration full emulation of snprintf() by _snprintf() is available in mingw-w64 stdio library: https://sourceforge.net/p/mingw-w64/mingw-w64/ci/master/tree/mingw-w64-crt/stdio/snprintf.c --- miniupnpc/connecthostport.c | 6 +++++- miniupnpc/minisoap.c | 6 +++++- miniupnpc/minissdpc.c | 6 +++++- miniupnpc/miniupnpc.c | 6 +++++- miniupnpc/miniwget.c | 6 +++++- miniupnpc/upnpc.c | 6 +++++- 6 files changed, 30 insertions(+), 6 deletions(-) diff --git a/miniupnpc/connecthostport.c b/miniupnpc/connecthostport.c index f3982e1..a798b38 100644 --- a/miniupnpc/connecthostport.c +++ b/miniupnpc/connecthostport.c @@ -19,7 +19,11 @@ #include #include #define MAXHOSTNAMELEN 64 -#define snprintf _snprintf +/* snprintf is supported by Visual Studio 2015, mingw-w64 8.0.0, mingw-w64 with ucrt, mingw-w64 or mingw32 with ansi stdio */ +#if (defined(_MSC_VER) && _MSC_VER < 1900) || (defined(__MINGW64_VERSION_MAJOR) && __MINGW64_VERSION_MAJOR < 8 && !defined(_UCRT) && !defined(__USE_MINGW_ANSI_STDIO)) || (defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) && !defined(__USE_MINGW_ANSI_STDIO)) +/* _snprintf does not fill nul byte at the end of buffer and returns -1 on overflow */ +#define snprintf(buf, size, fmt, ...) ((_snprintf((buf), (size), (fmt), __VA_ARGS__), (((char *)buf)[(size_t)(size)-1] = 0), _scprintf((fmt), __VA_ARGS__))) +#endif #define herror #define socklen_t int #else /* #ifdef _WIN32 */ diff --git a/miniupnpc/minisoap.c b/miniupnpc/minisoap.c index f92b36c..55d3e76 100644 --- a/miniupnpc/minisoap.c +++ b/miniupnpc/minisoap.c @@ -13,7 +13,11 @@ #ifdef _WIN32 #include #include -#define snprintf _snprintf +/* snprintf is supported by Visual Studio 2015, mingw-w64 8.0.0, mingw-w64 with ucrt, mingw-w64 or mingw32 with ansi stdio */ +#if (defined(_MSC_VER) && _MSC_VER < 1900) || (defined(__MINGW64_VERSION_MAJOR) && __MINGW64_VERSION_MAJOR < 8 && !defined(_UCRT) && !defined(__USE_MINGW_ANSI_STDIO)) || (defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) && !defined(__USE_MINGW_ANSI_STDIO)) +/* _snprintf does not fill nul byte at the end of buffer and returns -1 on overflow */ +#define snprintf(buf, size, fmt, ...) ((_snprintf((buf), (size), (fmt), __VA_ARGS__), (((char *)buf)[(size_t)(size)-1] = 0), _scprintf((fmt), __VA_ARGS__))) +#endif #else #include #include diff --git a/miniupnpc/minissdpc.c b/miniupnpc/minissdpc.c index 4f45dda..d12f42b 100644 --- a/miniupnpc/minissdpc.c +++ b/miniupnpc/minissdpc.c @@ -20,7 +20,11 @@ #include #include #include -#define snprintf _snprintf +/* snprintf is supported by Visual Studio 2015, mingw-w64 8.0.0, mingw-w64 with ucrt, mingw-w64 or mingw32 with ansi stdio */ +#if (defined(_MSC_VER) && _MSC_VER < 1900) || (defined(__MINGW64_VERSION_MAJOR) && __MINGW64_VERSION_MAJOR < 8 && !defined(_UCRT) && !defined(__USE_MINGW_ANSI_STDIO)) || (defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) && !defined(__USE_MINGW_ANSI_STDIO)) +/* _snprintf does not fill nul byte at the end of buffer and returns -1 on overflow */ +#define snprintf(buf, size, fmt, ...) ((_snprintf((buf), (size), (fmt), __VA_ARGS__), (((char *)buf)[(size_t)(size)-1] = 0), _scprintf((fmt), __VA_ARGS__))) +#endif #if !defined(_MSC_VER) #include #else /* !defined(_MSC_VER) */ diff --git a/miniupnpc/miniupnpc.c b/miniupnpc/miniupnpc.c index c702a85..bdaa175 100644 --- a/miniupnpc/miniupnpc.c +++ b/miniupnpc/miniupnpc.c @@ -15,7 +15,11 @@ #include #include #include -#define snprintf _snprintf +/* snprintf is supported by Visual Studio 2015, mingw-w64 8.0.0, mingw-w64 with ucrt, mingw-w64 or mingw32 with ansi stdio */ +#if (defined(_MSC_VER) && _MSC_VER < 1900) || (defined(__MINGW64_VERSION_MAJOR) && __MINGW64_VERSION_MAJOR < 8 && !defined(_UCRT) && !defined(__USE_MINGW_ANSI_STDIO)) || (defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) && !defined(__USE_MINGW_ANSI_STDIO)) +/* _snprintf does not fill nul byte at the end of buffer and returns -1 on overflow */ +#define snprintf(buf, size, fmt, ...) ((_snprintf((buf), (size), (fmt), __VA_ARGS__), (((char *)buf)[(size_t)(size)-1] = 0), _scprintf((fmt), __VA_ARGS__))) +#endif #define strdup _strdup #if !defined(_MSC_VER) #include diff --git a/miniupnpc/miniwget.c b/miniupnpc/miniwget.c index 618d4b7..6d148c6 100644 --- a/miniupnpc/miniwget.c +++ b/miniupnpc/miniwget.c @@ -15,7 +15,11 @@ #include #include #define MAXHOSTNAMELEN 64 -#define snprintf _snprintf +/* snprintf is supported by Visual Studio 2015, mingw-w64 8.0.0, mingw-w64 with ucrt, mingw-w64 or mingw32 with ansi stdio */ +#if (defined(_MSC_VER) && _MSC_VER < 1900) || (defined(__MINGW64_VERSION_MAJOR) && __MINGW64_VERSION_MAJOR < 8 && !defined(_UCRT) && !defined(__USE_MINGW_ANSI_STDIO)) || (defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) && !defined(__USE_MINGW_ANSI_STDIO)) +/* _snprintf does not fill nul byte at the end of buffer and returns -1 on overflow */ +#define snprintf(buf, size, fmt, ...) ((_snprintf((buf), (size), (fmt), __VA_ARGS__), (((char *)buf)[(size_t)(size)-1] = 0), _scprintf((fmt), __VA_ARGS__))) +#endif #define socklen_t int #ifndef strncasecmp #if defined(_MSC_VER) && (_MSC_VER >= 1400) diff --git a/miniupnpc/upnpc.c b/miniupnpc/upnpc.c index cb7f18b..549befd 100644 --- a/miniupnpc/upnpc.c +++ b/miniupnpc/upnpc.c @@ -11,7 +11,11 @@ #include #ifdef _WIN32 #include -#define snprintf _snprintf +/* snprintf is supported by Visual Studio 2015, mingw-w64 8.0.0, mingw-w64 with ucrt, mingw-w64 or mingw32 with ansi stdio */ +#if (defined(_MSC_VER) && _MSC_VER < 1900) || (defined(__MINGW64_VERSION_MAJOR) && __MINGW64_VERSION_MAJOR < 8 && !defined(_UCRT) && !defined(__USE_MINGW_ANSI_STDIO)) || (defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) && !defined(__USE_MINGW_ANSI_STDIO)) +/* _snprintf does not fill nul byte at the end of buffer and returns -1 on overflow */ +#define snprintf(buf, size, fmt, ...) ((_snprintf((buf), (size), (fmt), __VA_ARGS__), (((char *)buf)[(size_t)(size)-1] = 0), _scprintf((fmt), __VA_ARGS__))) +#endif #else /* for IPPROTO_TCP / IPPROTO_UDP */ #include