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