[PATCH] buffer overflow checking for string functions

Marcus Meissner marcus at jet.franken.de
Thu Sep 4 03:24:30 CDT 2008


Hi,

This patch adds buffer overflow checking for MBtoWC, WCtoMB,
and lstrcpy* functions.

I am using this for quite some time now in both my local
and the openSUSE Wine tree, but have replaced abort()s by
RaiseException()s now to get more Windows like backtraces.

Ciao, Marcus
---
 dlls/kernel32/locale.c         |    2 +
 dlls/kernel32/tests/codepage.c |    3 ++
 include/winbase.h              |   50 +++++++++++++++++++++++++++++++--------
 include/winnls.h               |   51 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 96 insertions(+), 10 deletions(-)

diff --git a/dlls/kernel32/locale.c b/dlls/kernel32/locale.c
index 8aedacb..c72d05e 100644
--- a/dlls/kernel32/locale.c
+++ b/dlls/kernel32/locale.c
@@ -1796,6 +1796,7 @@ BOOL WINAPI EnumSystemCodePagesW( CODEPAGE_ENUMPROCW lpfnCodePageEnum, DWORD fla
  *            is passed, and ERROR_NO_UNICODE_TRANSLATION if no translation is
  *            possible for src.
  */
+#undef MultiByteToWideChar
 INT WINAPI MultiByteToWideChar( UINT page, DWORD flags, LPCSTR src, INT srclen,
                                 LPWSTR dst, INT dstlen )
 {
@@ -1887,6 +1888,7 @@ INT WINAPI MultiByteToWideChar( UINT page, DWORD flags, LPCSTR src, INT srclen,
  *            and dstlen != 0, and ERROR_INVALID_PARAMETER, if an invalid
  *            parameter was given.
  */
+#undef WideCharToMultiByte
 INT WINAPI WideCharToMultiByte( UINT page, DWORD flags, LPCWSTR src, INT srclen,
                                 LPSTR dst, INT dstlen, LPCSTR defchar, BOOL *used )
 {
diff --git a/dlls/kernel32/tests/codepage.c b/dlls/kernel32/tests/codepage.c
index c7daf19..2275f0f 100644
--- a/dlls/kernel32/tests/codepage.c
+++ b/dlls/kernel32/tests/codepage.c
@@ -127,6 +127,9 @@ static void test_negative_source_length(void)
     char buf[10];
     WCHAR bufW[10];
 
+#undef WideCharToMultiByte
+#undef MultiByteToWideChar
+
     /* Test, whether any negative source length works as strlen() + 1 */
     SetLastError( 0xdeadbeef );
     memset(buf,'x',sizeof(buf));
diff --git a/include/winbase.h b/include/winbase.h
index 5969558..f92d40e 100644
--- a/include/winbase.h
+++ b/include/winbase.h
@@ -2145,11 +2145,24 @@ WINBASEAPI INT         WINAPI lstrlenW(LPCWSTR);
 
 /* string functions without the exception handler */
 
+#if defined(__GNUC__) && (__GNUC__ < 4)
+# define __builtin_object_size(x,y) -1
+#endif
+
 extern inline LPWSTR WINAPI lstrcpynW( LPWSTR dst, LPCWSTR src, INT n )
 {
     LPWSTR d = dst;
     LPCWSTR s = src;
     UINT count = n;
+    INT dlen = __builtin_object_size(dst,0);
+
+    if ((dlen != -1) && (count*sizeof(WCHAR) > dlen))
+	RaiseException(0xC0000409,0x01,0,NULL);
+
+    if (__builtin_object_size(dst, 1) != -1) {
+    	if (__builtin_object_size(dst, 1) < n*sizeof(WCHAR))
+		RaiseException(0xC0000409,0x01,0,NULL);
+    }
 
     while ((count > 1) && *s)
     {
@@ -2165,6 +2178,10 @@ extern inline LPSTR WINAPI lstrcpynA( LPSTR dst, LPCSTR src, INT n )
     LPSTR d = dst;
     LPCSTR s = src;
     UINT count = n;
+    INT dlen = __builtin_object_size(dst,0);
+
+    if ((dlen != -1) && (count > dlen))
+	RaiseException(0xC0000409,0x01,0,NULL);
 
     while ((count > 1) && *s)
     {
@@ -2190,27 +2207,40 @@ extern inline INT WINAPI lstrlenA( LPCSTR str )
 extern inline LPWSTR WINAPI lstrcpyW( LPWSTR dst, LPCWSTR src )
 {
     WCHAR *p = dst;
-    while ((*p++ = *src++));
+    INT dlen = __builtin_object_size(dst,0);
+    INT slen = __builtin_object_size(src,0);
+
+    if ((slen!=-1) && (dlen!=-1) && (slen > dlen))
+	RaiseException(0xC0000409,0x01,0,NULL);
+
+    if (dlen != -1) {
+    	while ((dlen-- >= 0) && (*p++ = *src++));
+	if (dlen == -1) RaiseException(0xC0000409,0x01,0,NULL);
+    } else {
+    	while ((*p++ = *src++));
+    }
     return dst;
 }
 
-extern inline LPSTR WINAPI lstrcpyA( LPSTR dst, LPCSTR src )
-{
-    return strcpy( dst, src );
-}
+#define lstrcpyA strcpy
 
 extern inline LPWSTR WINAPI lstrcatW( LPWSTR dst, LPCWSTR src )
 {
     WCHAR *p = dst;
+    INT dlen = __builtin_object_size(dst,0);
+
     while (*p) p++;
-    while ((*p++ = *src++));
+    if (dlen != -1) {
+	dlen -= p-dst;
+	while ((dlen-- >=0 ) && (*p++ = *src++));
+	if (dlen == -1) RaiseException(0xC0000409,0x01,0,NULL);
+    } else {
+	while ((*p++ = *src++));
+    }
     return dst;
 }
 
-extern inline LPSTR WINAPI lstrcatA( LPSTR dst, LPCSTR src )
-{
-    return strcat( dst, src );
-}
+#define lstrcatA strcat
 
 /* strncpy doesn't do what you think, don't use it */
 #undef strncpy
diff --git a/include/winnls.h b/include/winnls.h
index 50d6389..033231e 100644
--- a/include/winnls.h
+++ b/include/winnls.h
@@ -788,6 +788,57 @@ WINBASEAPI BOOL        WINAPI SetThreadLocale(LCID);
 WINBASEAPI BOOL        WINAPI SetUserGeoID(GEOID);
 WINBASEAPI INT         WINAPI WideCharToMultiByte(UINT,DWORD,LPCWSTR,INT,LPSTR,INT,LPCSTR,LPBOOL);
 
+#if defined(__GNUC__) && (__GNUC__ < 4)
+# undef __builtin_object_size
+# define __builtin_object_size(x,y) -1
+#endif
+
+#ifndef STATUS_STACK_BUFFER_OVERRUN
+# define STATUS_STACK_BUFFER_OVERRUN      0xC0000409
+#endif
+#ifndef EH_NONCONTINUABLE
+# define EH_NONCONTINUABLE 0x01
+#endif
+static inline INT
+WINAPI MultiByteToWideChar_ichk(
+	UINT cp,DWORD flags,
+	LPCSTR src,INT srclen,INT srcbuflen,
+	LPWSTR dst,INT dstlen,INT dstbuflen
+) {
+	if ((srclen != -1) && (srcbuflen != -1) && (srcbuflen < srclen))
+		RaiseException(0xC0000409,0x01,0,NULL);
+	if ((dstlen != -1)  && (dstbuflen != -1) && (dstbuflen/2 < dstlen))
+		RaiseException(0xC0000409,0x01,0,NULL);
+	/* later add assertions regarding conversion lengths */
+	return MultiByteToWideChar(cp,flags,src,srclen,dst,dstlen);
+}
+#define MultiByteToWideChar(cp,flags,src,srclen,dst,dstlen)	\
+	MultiByteToWideChar_ichk(cp,flags,			\
+		src,srclen,__builtin_object_size(src,0),	\
+		dst,dstlen,__builtin_object_size(dst,0)		\
+	)
+
+static inline INT
+WINAPI WideCharToMultiByte_ichk(
+	UINT cp,DWORD flags,
+	LPCWSTR src,INT srclen,INT srcbuflen,
+	LPSTR dst,INT dstlen,INT dstbuflen,
+	LPCSTR xstr,LPBOOL b
+) {
+	if ((srclen != -1) && (srcbuflen != -1) && (srcbuflen/2 < srclen))
+		RaiseException(0xC0000409,0x01,0,NULL);
+	if ((dstlen != -1)  && (dstbuflen != -1) && (dstbuflen < dstlen))
+		RaiseException(0xC0000409,0x01,0,NULL);
+	/* later add assertions regarding conversion lengths */
+	return WideCharToMultiByte(cp,flags,src,srclen,dst,dstlen,xstr,b);
+}
+#define WideCharToMultiByte(cp,flags,src,srclen,dst,dstlen,defchar,b)	\
+	WideCharToMultiByte_ichk(cp,flags,				\
+		src,srclen,__builtin_object_size(src,0),		\
+		dst,dstlen,__builtin_object_size(dst,0),		\
+		defchar,b							\
+	)
+
 #ifdef __cplusplus
 }
 #endif
-- 
1.5.2.4



More information about the wine-patches mailing list