Hi,

packages from Linux and *BSD distros are often build with -D_FORTIFY_SOURCE=2 set by default. This enables buffer overflow checks for functions like strcpy() if buffer size is known at compile time.

Attached is an experimental patch that adds some _FORTIFY_SOURCE support to Mingw-w64 string.h and stdio.h. The test program shows the code modification as comments. I verified this in assembly output x86_64-w64-mingw-gcc and ...-g++.

Supported functions: memcpy(), memset(), strcpy(), strcat(), strncpy(), strncat(), snprintf(), vsnprintf(), and for __USE_MINGW_ANSI_STDIO only: sprintf(), vsprintf(), snwprintf(), vsnwprintf(),

The GCC __builtin___*_chk() functions are not used for now because the required _*_chk() library functions are not available.

The patch also shows how varargs *printf() wrappers could be rewritten if compiler supports __builtin_va_arg_pack().

Thanks for any comment.

--
Regards,
Christian

diff --git a/include/_mingw_mac.h b/include/_mingw_mac.h
index c5d1a0d..b7db125 100644
--- a/include/_mingw_mac.h
+++ b/include/_mingw_mac.h
@@ -291,6 +291,36 @@
 #  define __mingw_static_ovr __mingw_ovr
 #endif /* __cplusplus */
 
+#undef __mingw_va_arg_pack_ovr
+#if __MINGW_GNUC_PREREQ (4, 3) && !defined (__clang__)
+#  define __mingw_va_arg_pack_ovr __mingw_ovr 
__attribute__((__always_inline__))
+#endif
+
+#if _FORTIFY_SOURCE > 0 && __OPTIMIZE__ > 0 && __MINGW_GNUC_PREREQ (4, 3)
+#  if _FORTIFY_SOURCE > 1
+#    define __MINGW_FORTIFY_LEVEL 2
+#  else
+#    define __MINGW_FORTIFY_LEVEL 1
+#  endif
+#else
+#  define __MINGW_FORTIFY_LEVEL 0
+#endif
+
+#if __MINGW_FORTIFY_LEVEL > 0
+#  define __mingw_bos_declare void __chk_fail() __attribute__((__noreturn__))
+#  define __mingw_bos(p) __builtin_object_size((p), (__MINGW_FORTIFY_LEVEL > 
1))
+#  define __mingw_bos_known(p) (__mingw_bos(p) != (size_t)-1)
+#  define __mingw_bos_cond_chk(c) (__builtin_expect((c), 1) ? (void)0 : 
__chk_fail())
+#  define __mingw_bos_ptr_chk(p, n) __mingw_bos_cond_chk( \
+     !__mingw_bos_known(p) || __mingw_bos(p) >= (size_t)(n))
+#  define __mingw_bos_ovr __mingw_ovr \
+     __attribute__((__always_inline__, __gnu_inline__))
+#  define __mingw_extern_bos_ovr extern __inline__ __cdecl \
+     __attribute__((__always_inline__, __gnu_inline__))
+#else
+#  define __mingw_bos_ovr __mingw_ovr
+#endif /* __MINGW_FORTIFY_LEVEL > 0 */
+
 /* Enable workaround for ABI incompatibility on affected platforms */
 #ifndef WIDL_EXPLICIT_AGGREGATE_RETURNS
 #if defined(__GNUC__) && defined(__cplusplus) && (defined(__x86_64__) || 
defined(__i386__))
diff --git a/include/stdio.h b/include/stdio.h
index e183236..aba2aa2 100644
--- a/include/stdio.h
+++ b/include/stdio.h
@@ -156,6 +156,10 @@ extern FILE (* __MINGW_IMP_SYMBOL(_iob))[];        /* A 
pointer to an array of FILE */
 #endif
 #endif
 
+#if __MINGW_FORTIFY_LEVEL > 0
+__mingw_bos_declare;
+#endif
+
 #ifndef _STDIO_DEFINED
 extern
   __attribute__((__format__ (gnu_scanf, 2, 3))) __MINGW_ATTRIB_NONNULL(2)
@@ -349,6 +353,28 @@ int printf (const char *__format, ...)
   return __retval;
 }
 
+#ifdef __mingw_va_arg_pack_ovr
+
+__mingw_va_arg_pack_ovr
+__attribute__((__format__ (gnu_printf, 2, 3))) __MINGW_ATTRIB_NONNULL(2)
+int sprintf (char *__stream, const char *__format, ...)
+{
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
+#if __MINGW_FORTIFY_LEVEL > 0
+  if (__mingw_bos_known(__stream)) {
+    int __retval = __mingw_snprintf( __stream, __mingw_bos(__stream), 
__format, __builtin_va_arg_pack() );
+    if (__retval >= 0)
+      __mingw_bos_ptr_chk(__stream, (size_t)__retval + 1);
+    return __retval;
+  }
+#endif
+  return __mingw_sprintf( __stream, __format, __builtin_va_arg_pack() );
+#pragma GCC diagnostic pop
+}
+
+#else /* !__mingw_va_arg_pack_ovr */
+
 __mingw_ovr
 __attribute__((__format__ (gnu_printf, 2, 3))) __MINGW_ATTRIB_NONNULL(2)
 int sprintf (char *__stream, const char *__format, ...)
@@ -360,6 +386,8 @@ int sprintf (char *__stream, const char *__format, ...)
   return __retval;
 }
 
+#endif /* __mingw_va_arg_pack_ovr */
+
 __mingw_ovr
 __attribute__((__format__ (gnu_printf, 2, 0))) __MINGW_ATTRIB_NONNULL(2)
 int vfprintf (FILE *__stream, const char *__format, __builtin_va_list 
__local_argv)
@@ -374,13 +402,39 @@ int vprintf (const char *__format, __builtin_va_list 
__local_argv)
   return __mingw_vfprintf( stdout, __format, __local_argv );
 }
 
-__mingw_ovr
+__mingw_bos_ovr
 __attribute__((__format__ (gnu_printf, 2, 0))) __MINGW_ATTRIB_NONNULL(2)
 int vsprintf (char *__stream, const char *__format, __builtin_va_list 
__local_argv)
 {
+#if __MINGW_FORTIFY_LEVEL > 0
+  if (__mingw_bos_known(__stream)) {
+    int __retval = __mingw_vsnprintf( __stream, __mingw_bos(__stream), 
__format, __local_argv );
+    if (__retval >= 0)
+      __mingw_bos_ptr_chk(__stream, (size_t)__retval + 1);
+    return __retval;
+  }
+#endif
   return __mingw_vsprintf( __stream, __format, __local_argv );
 }
 /* #ifndef __NO_ISOCEXT */  /* externs in libmingwex.a */
+
+#ifdef __mingw_va_arg_pack_ovr
+
+__mingw_va_arg_pack_ovr
+__attribute__((__format__ (gnu_printf, 3, 4))) __MINGW_ATTRIB_NONNULL(3)
+int snprintf (char *__stream, size_t __n, const char *__format, ...)
+{
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
+#if __MINGW_FORTIFY_LEVEL > 0
+  __mingw_bos_ptr_chk(__stream, __n);
+#endif
+  return __mingw_snprintf( __stream, __n, __format, __builtin_va_arg_pack() );
+#pragma GCC diagnostic pop
+}
+
+#else /* !__mingw_va_arg_pack_ovr */
+
 __mingw_ovr
 __attribute__((__format__ (gnu_printf, 3, 4))) __MINGW_ATTRIB_NONNULL(3)
 int snprintf (char *__stream, size_t __n, const char *__format, ...)
@@ -392,10 +446,15 @@ int snprintf (char *__stream, size_t __n, const char 
*__format, ...)
   return __retval;
 }
 
-__mingw_ovr
+#endif /* __mingw_va_arg_pack_ovr */
+
+__mingw_bos_ovr
 __attribute__((__format__ (gnu_printf, 3, 0))) __MINGW_ATTRIB_NONNULL(3)
 int vsnprintf (char *__stream, size_t __n, const char *__format, 
__builtin_va_list __local_argv)
 {
+#if __MINGW_FORTIFY_LEVEL > 0
+  __mingw_bos_ptr_chk(__stream, __n);
+#endif
   return __mingw_vsnprintf( __stream, __n, __format, __local_argv );
 }
 
@@ -765,10 +824,13 @@ int vsnprintf (char *__stream, size_t __n, const char 
*__format, __builtin_va_li
   int __cdecl __ms_vsnprintf(char * __restrict__ d,size_t n,const char * 
__restrict__ format,va_list arg)
     __MINGW_ATTRIB_DEPRECATED_MSVC2005 __MINGW_ATTRIB_DEPRECATED_SEC_WARN;
 
-  __mingw_ovr
+  __mingw_bos_ovr
   __attribute__((__format__ (ms_printf, 3, 0))) __MINGW_ATTRIB_NONNULL(3)
   int vsnprintf (char * __restrict__ __stream, size_t __n, const char * 
__restrict__ __format, va_list __local_argv)
   {
+#if __MINGW_FORTIFY_LEVEL > 0
+    __mingw_bos_ptr_chk(__stream, __n);
+#endif
     return __ms_vsnprintf (__stream, __n, __format, __local_argv);
   }
 
@@ -776,6 +838,23 @@ int vsnprintf (char *__stream, size_t __n, const char 
*__format, __builtin_va_li
   int __cdecl __ms_snprintf(char * __restrict__ s, size_t n, const char * 
__restrict__  format, ...);
 
 #ifndef __NO_ISOCEXT
+#ifdef __mingw_va_arg_pack_ovr
+
+__mingw_va_arg_pack_ovr
+__attribute__((__format__ (ms_printf, 3, 4))) __MINGW_ATTRIB_NONNULL(3)
+int snprintf (char * __restrict__ __stream, size_t __n, const char * 
__restrict__ __format, ...)
+{
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
+#if __MINGW_FORTIFY_LEVEL > 0
+  __mingw_bos_ptr_chk(__stream, __n);
+#endif
+  return __ms_snprintf(__stream, __n, __format, __builtin_va_arg_pack());
+#pragma GCC diagnostic pop
+}
+
+#else /* !__mingw_va_arg_pack_ovr */
+
 __mingw_ovr
 __attribute__((__format__ (ms_printf, 3, 4))) __MINGW_ATTRIB_NONNULL(3)
 int snprintf (char * __restrict__ __stream, size_t __n, const char * 
__restrict__ __format, ...)
@@ -786,6 +865,8 @@ int snprintf (char * __restrict__ __stream, size_t __n, 
const char * __restrict_
   __builtin_va_end( __local_argv );
   return __retval;
 }
+
+#endif /* !__mingw_va_arg_pack_ovr */
 #endif /* !__NO_ISOCEXT */
 
 #pragma pop_macro ("vsnprintf")
@@ -949,6 +1030,21 @@ int vwprintf (const wchar_t *__format, __builtin_va_list 
__local_argv)
 }
 
 #ifndef __NO_ISOCEXT  /* externs in libmingwex.a */
+
+#ifdef __mingw_va_arg_pack_ovr
+
+__mingw_va_arg_pack_ovr
+/* __attribute__((__format__ (gnu_wprintf, 3, 4))) */ __MINGW_ATTRIB_NONNULL(3)
+int snwprintf (wchar_t *__stream, size_t __n, const wchar_t *__format, ...)
+{
+#if __MINGW_FORTIFY_LEVEL > 0
+  __mingw_bos_ptr_chk(__stream, __n * sizeof(wchar_t));
+#endif
+  return __mingw_snwprintf( __stream, __n, __format, __builtin_va_arg_pack() );
+}
+
+#else /* !__mingw_va_arg_pack_ovr */
+
 __mingw_ovr
 /* __attribute__((__format__ (gnu_wprintf, 3, 4))) */ __MINGW_ATTRIB_NONNULL(3)
 int snwprintf (wchar_t *__stream, size_t __n, const wchar_t *__format, ...)
@@ -960,10 +1056,15 @@ int snwprintf (wchar_t *__stream, size_t __n, const 
wchar_t *__format, ...)
   return __retval;
 }
 
-__mingw_ovr
+#endif /* __mingw_va_arg_pack_ovr */
+
+__mingw_bos_ovr
 /* __attribute__((__format__ (gnu_wprintf, 3, 0))) */ __MINGW_ATTRIB_NONNULL(3)
 int vsnwprintf (wchar_t *__stream, size_t __n, const wchar_t *__format, 
__builtin_va_list __local_argv)
 {
+#if __MINGW_FORTIFY_LEVEL > 0
+  __mingw_bos_ptr_chk(__stream, __n * sizeof(wchar_t));
+#endif
   return __mingw_vsnwprintf( __stream, __n, __format, __local_argv );
 }
 #endif /* __NO_ISOCEXT */
diff --git a/include/string.h b/include/string.h
index c8c8018..d74ef5f 100644
--- a/include/string.h
+++ b/include/string.h
@@ -188,4 +188,68 @@ extern "C" {
 #endif
 
 #include <sec_api/string_s.h>
+
+#if __MINGW_FORTIFY_LEVEL > 0
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+__mingw_bos_declare;
+
+__mingw_extern_bos_ovr
+void * __cdecl memcpy(void * __restrict__ __dst, const void * __restrict__ 
__src, size_t __n)
+{
+  __mingw_bos_ptr_chk(__dst, __n);
+  return __builtin_memcpy(__dst, __src, __n);
+}
+
+__mingw_extern_bos_ovr
+void * __cdecl memset(void * __dst, int __val, size_t __n)
+{
+  __mingw_bos_ptr_chk(__dst, __n);
+  return __builtin_memset(__dst, __val, __n);
+}
+
+__mingw_extern_bos_ovr
+char * __cdecl strcpy(char * __restrict__ __dst, const char * __restrict__ 
__src)
+{
+  if (__mingw_bos_known(__dst)) {
+    __mingw_bos_cond_chk( !strcpy_s(__dst, __mingw_bos(__dst), __src) );
+    return __dst;
+  }
+  return __builtin_strcpy(__dst, __src);
+}
+
+__mingw_extern_bos_ovr
+char * __cdecl strcat(char * __restrict__ __dst, const char * __restrict__ 
__src)
+{
+  if (__mingw_bos_known(__dst)) {
+    __mingw_bos_cond_chk( !strcat_s(__dst, __mingw_bos(__dst), __src) );
+    return __dst;
+  }
+  return __builtin_strcat(__dst, __src);
+}
+
+__mingw_extern_bos_ovr
+char * __cdecl strncpy(char * __restrict__ __dst, const char * __restrict__ 
__src, size_t __n)
+{
+  __mingw_bos_ptr_chk(__dst, __n);
+  return __builtin_strncpy(__dst, __src, __n);
+}
+
+__mingw_extern_bos_ovr
+char * __cdecl strncat(char * __restrict__ __dst, const char * __restrict__ 
__src, size_t __n)
+{
+  if (__mingw_bos_known(__dst)) {
+    __mingw_bos_cond_chk( !strncat_s(__dst, __mingw_bos(__dst), __src, __n) );
+    return __dst;
+  }
+  return __builtin_strncat(__dst, __src, __n);
+}
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __MINGW_FORTIFY_LEVEL > 0 */
+
 #endif
#define _FORTIFY_SOURCE 2
#define __USE_MINGW_ANSI_STDIO 1

#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char buf1[13];
char * buf2 = buf1;

void  * test_mcp_1(const void *s, size_t n)
{
  // if (n > 13) __chk_fail();
  return memcpy(buf1, s, n);
}
void * test_mcp_2(const void *s, size_t n)
{
  return memcpy(buf2, s, n);
}
void  * test_mst_1(size_t n)
{
  // if (n > 13) __chk_fail();
  return memset(buf1, 0, n);
}
void * test_mst_2(size_t n)
{
  return memset(buf2, 0, n);
}
char * test_scp_1(const char *s)
{
  // if (strcpy_s(buf1, 13, s)) __chk_fail();
  // return buf1;
  return strcpy(buf1, s);
}
char * test_scp_2(const char *s)
{
  return strcpy(buf2, s);
}
char * test_sct_1(const char *s)
{
  // if (strcat_s(buf1, 13, s)) __chk_fail();
  // return buf1;
  return strcat(buf1, s);
}
char * test_sct_2(const char *s)
{
  return strcat(buf2, s);
}
char * test_sncp_1(const char *s, size_t n)
{
  // if (n > 13) __chk_fail();
  return strncpy(buf1, s, n);
}
char * test_sncp_2(const char *s, size_t n)
{
  return strncpy(buf2, s, n);
}
char * test_snct_1(const char *s, size_t n)
{
  // if (strncat_s(buf1, 13, s, n)) __chk_fail();
  // return buf1;
  return strncat(buf1, s, n);
}
char * test_snct_2(const char *s, size_t n)
{
  return strncat(buf2, s, n);
}

int test_spf_1(const char *s)
{
  // int n = snprintf(buf1, 13, "%s\n", s);
  // if (n > 12) __chk_fail();
  // return n;
  return sprintf(buf1, "%s\n", s);
}
int test_spf_2(const char *s)
{
  return sprintf(buf2, "%s\n", s);
}
int test_snpf_1(const char *s)
{
  return snprintf(buf1, sizeof(buf1), "%s\n", s);
}
int test_snpf_2(const char *s)
{
  return snprintf(buf2, sizeof(buf1), "%s\n", s);
}
int test_snpf_1_n(const char *s, size_t n)
{
  // if (n > 13) __chk_fail();
  return snprintf(buf1, n, "%s\n", s);
}
int test_snpf_2_n(const char *s, size_t n)
{
  return snprintf(buf2, n, "%s\n", s);
}
int test_snpf_1_x(const char *s)
{
  // __chk_fail();
  return snprintf(buf1, sizeof(buf1)+1, "%s\n", s);
}
int test_snpf_2_x(const char *s)
{
  return snprintf(buf2, sizeof(buf1)+1, "%s\n", s);
}

int test_vspf_1(const char *fmt, ...)
{
  va_list args; va_start(args, fmt);
  // int r = vsnprintf(buf1, 13, args);
  // va_end(args);
  // if (r > 12) __chk_fail();
  // return r;
  int r = vsprintf(buf1, fmt, args);
  va_end(args);
  return r;
}
int test_vsnpf_1(size_t n, const char *fmt, ...)
{
  // if (n > 13) __chk_fail();
  va_list args; va_start(args, fmt);
  int r = vsnprintf(buf1, n, fmt, args);
  va_end(args);
  return r;
}

wchar_t wbuf1[13];
wchar_t * wbuf2 = wbuf1;

int test_snwpf_1_n(const wchar_t *s, size_t n)
{
  // if (n*2 > 26) __chk_fail();
  return snwprintf(wbuf1, n, L"%s\n", s);
}
int test_snwpf_2_n(const wchar_t *s, size_t n)
{
  return snwprintf(wbuf2, n, L"%s\n", s);
}

// Check _FORTIFY_SOURCE 1 vs. 2
struct { char b1[13]; char b2[42]; } sbuf;

void * test_mst_sbuf(size_t n)
{
  // if (n > (_FORTIFY_SOURCE > 1 ? 13 : 55)) __chk_fail();
  return memset(sbuf.b1, 0, n);
}

int main(int argc, char **argv)
{
  if (argc <= 1)
    return 1;
  const char * s = (argc > 2 ? argv[2] : "");
  const char * p = (argc > 3 ? argv[3] : "");
  size_t n = strlen(s);
  switch (atoi(argv[1])) {
    case 0: test_mcp_1(s, n+1); break;
    case 1: test_mst_1(n+1); break;
    case 2: test_scp_1(s); break;
    case 3: test_scp_1(s); test_sct_1(p); break;
    case 4: test_sncp_1(s, n); break;
    case 5: test_scp_1(s); test_snct_1(p, n); break;
    case 6: test_spf_1(s); break;
    case 7: test_snpf_1(s); break;
    case 8: test_snpf_1_n(p, n+1); break;
    case 9: test_snpf_1_x(s); break;
    case 10: test_vspf_1("%s.", s); break;
    case 11: test_vsnpf_1(n+1, "%s.", p); break;
  }
  printf("%s.\n", buf1); fflush(stdout);
  return 0;
}
_______________________________________________
Mingw-w64-public mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public

Reply via email to