Hi,

the attached patch fixes a stack overflow in __mingw_wcstof and
__mingw_wcstold.

I've also attached a small reproducer for the bug.

Interestingly the bugged functions are only called if using C++ and if
windows.h is included before wchar.h

Regards,
Tim Kosse
From 283f3f991089af0c81327cebdd9421714b2a076e Mon Sep 17 00:00:00 2001
From: Tim Kosse <tim.ko...@filezilla-project.org>
Date: Tue, 18 Feb 2020 12:31:14 +0100
Subject: [PATCH] Fix stack overflow in __mingw_wcstof and __mingw_wcstold

Use regular malloc instead of alloca as the caller might potentially
pass a very large string exceeding the size of the stack.

Signed-off-by: Tim Kosse <tim.ko...@filezilla-project.org>
---
 mingw-w64-crt/misc/mingw_wcstof.c  |  9 ++++++++-
 mingw-w64-crt/misc/mingw_wcstold.c | 10 +++++++++-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/mingw-w64-crt/misc/mingw_wcstof.c 
b/mingw-w64-crt/misc/mingw_wcstof.c
index 6cdf2e06..25f2aacd 100644
--- a/mingw-w64-crt/misc/mingw_wcstof.c
+++ b/mingw-w64-crt/misc/mingw_wcstof.c
@@ -12,7 +12,13 @@ __mingw_wcstof (const wchar_t * __restrict__ _Str, wchar_t 
** __restrict__ _EndP
   size_t l, l2;
 
   l = WideCharToMultiByte(CP_UTF8, 0, _Str, -1, NULL, 0, NULL, NULL);
-  n = alloca (l + 1);
+  n = malloc (l + 1);
+  if (!n)
+  {
+    if (_EndPtr)
+      *_EndPtr = Str;
+    return 0.0;
+  }
   if (l != 0) WideCharToMultiByte (CP_UTF8, 0, _Str, -1, n, l, NULL, NULL);
   n[l] = 0;
   r = __mingw_strtof (n, &ep);  
@@ -26,6 +32,7 @@ __mingw_wcstof (const wchar_t * __restrict__ _Str, wchar_t ** 
__restrict__ _EndP
   }
   else
    if (_EndPtr) *_EndPtr = NULL;
+  free(n);
   return r;
 }
 
diff --git a/mingw-w64-crt/misc/mingw_wcstold.c 
b/mingw-w64-crt/misc/mingw_wcstold.c
index ce1ad5e0..66ee5573 100644
--- a/mingw-w64-crt/misc/mingw_wcstold.c
+++ b/mingw-w64-crt/misc/mingw_wcstold.c
@@ -12,7 +12,14 @@ __mingw_wcstold (const wchar_t * __restrict__ _Str, wchar_t 
** __restrict__ _End
   size_t l, l2;
 
   l = WideCharToMultiByte(CP_UTF8, 0, _Str, -1, NULL, 0, NULL, NULL);
-  n = alloca (l + 1);
+  n = malloc (l + 1);
+  if (!n)
+  {
+    if (_EndPtr)
+      *_EndPtr = Str;
+    return 0.0;
+  }
+
   if (l != 0) WideCharToMultiByte (CP_UTF8, 0, _Str, -1, n, l, NULL, NULL);
   n[l] = 0;
   r = __mingw_strtold (n, &ep);  
@@ -27,6 +34,7 @@ __mingw_wcstold (const wchar_t * __restrict__ _Str, wchar_t 
** __restrict__ _End
   }
   else if (_EndPtr)
    *_EndPtr = NULL;
+  free(n);
   return r;
 }
 
-- 
2.25.1

        .file   "crash.cpp"
        .text
        .section        .text$wcstod,"x"
        .linkonce discard
        .globl  wcstod
        .def    wcstod; .scl    2;      .type   32;     .endef
        .seh_proc       wcstod
wcstod:
.LFB265:
        pushq   %rbp
        .seh_pushreg    %rbp
        movq    %rsp, %rbp
        .seh_setframe   %rbp, 0
        subq    $32, %rsp
        .seh_stackalloc 32
        .seh_endprologue
        movq    %rcx, 16(%rbp)
        movq    %rdx, 24(%rbp)
        movq    24(%rbp), %rax
        movq    %rax, %rdx
        movq    16(%rbp), %rcx
        call    __mingw_wcstod
        addq    $32, %rsp
        popq    %rbp
        ret
        .seh_endproc
        .text
        .def    _ZL6printfPKcz; .scl    3;      .type   32;     .endef
        .seh_proc       _ZL6printfPKcz
_ZL6printfPKcz:
.LFB4823:
        pushq   %rbp
        .seh_pushreg    %rbp
        pushq   %rbx
        .seh_pushreg    %rbx
        subq    $56, %rsp
        .seh_stackalloc 56
        leaq    128(%rsp), %rbp
        .seh_setframe   %rbp, 128
        .seh_endprologue
        movq    %rcx, -48(%rbp)
        movq    %rdx, -40(%rbp)
        movq    %r8, -32(%rbp)
        movq    %r9, -24(%rbp)
        leaq    -40(%rbp), %rax
        movq    %rax, -96(%rbp)
        movq    -96(%rbp), %rbx
        movl    $1, %ecx
        movq    __imp___acrt_iob_func(%rip), %rax
        call    *%rax
        movq    %rbx, %r8
        movq    -48(%rbp), %rdx
        movq    %rax, %rcx
        call    __mingw_vfprintf
        movl    %eax, -84(%rbp)
        movl    -84(%rbp), %eax
        addq    $56, %rsp
        popq    %rbx
        popq    %rbp
        ret
        .seh_endproc
        .section .rdata,"dr"
_ZStL19piecewise_construct:
        .space 1
.lcomm _ZStL8__ioinit,1,1
        .def    __main; .scl    2;      .type   32;     .endef
.LC0:
        .ascii "crash.cpp\0"
.LC1:
        .ascii "buf\0"
.LC2:
        .ascii "About to call wcstod\0"
        .align 8
.LC3:
        .ascii "If you see this it did not crash, we got %lf\12\0"
        .text
        .globl  main
        .def    main;   .scl    2;      .type   32;     .endef
        .seh_proc       main
main:
.LFB6339:
        pushq   %rbp
        .seh_pushreg    %rbp
        movq    %rsp, %rbp
        .seh_setframe   %rbp, 0
        subq    $80, %rsp
        .seh_stackalloc 80
        .seh_endprologue
        call    __main
        movq    $5000000, -16(%rbp)
        movq    -16(%rbp), %rax
        movabsq $4611686018427387900, %rdx
        cmpq    %rdx, %rax
        ja      .L6
        addq    %rax, %rax
        movq    %rax, %rcx
        call    _Znay
        movq    %rax, -24(%rbp)
        cmpq    $0, -24(%rbp)
        jne     .L9
        jmp     .L14
.L6:
        call    __cxa_throw_bad_array_new_length
.L14:
        movl    $14, %r8d
        leaq    .LC0(%rip), %rdx
        leaq    .LC1(%rip), %rcx
        movq    __imp__assert(%rip), %rax
        call    *%rax
.L9:
        movq    $0, -8(%rbp)
.L11:
        movq    -16(%rbp), %rax
        subq    $1, %rax
        cmpq    %rax, -8(%rbp)
        jnb     .L10
        movq    -8(%rbp), %rax
        leaq    (%rax,%rax), %rdx
        movq    -24(%rbp), %rax
        addq    %rdx, %rax
        movw    $48, (%rax)
        addq    $1, -8(%rbp)
        jmp     .L11
.L10:
        movq    -16(%rbp), %rax
        addq    %rax, %rax
        leaq    -2(%rax), %rdx
        movq    -24(%rbp), %rax
        addq    %rdx, %rax
        movw    $0, (%rax)
        movq    $0, -40(%rbp)
        leaq    .LC2(%rip), %rdx
        movq    .refptr._ZSt4cerr(%rip), %rcx
        call    _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
        movq    
.refptr._ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_(%rip), %rdx
        movq    %rax, %rcx
        call    _ZNSolsEPFRSoS_E
        leaq    -40(%rbp), %rdx
        movq    -24(%rbp), %rax
        movq    %rax, %rcx
        call    wcstod
        movq    %xmm0, %rax
        movq    %rax, -32(%rbp)
        movsd   -32(%rbp), %xmm0
        movq    -32(%rbp), %rax
        movapd  %xmm0, %xmm1
        movq    %rax, %rdx
        leaq    .LC3(%rip), %rcx
        call    _ZL6printfPKcz
        cmpq    $0, -24(%rbp)
        je      .L12
        movq    -24(%rbp), %rax
        movq    %rax, %rcx
        call    _ZdaPv
.L12:
        movl    $0, %eax
        addq    $80, %rsp
        popq    %rbp
        ret
        .seh_endproc
        .def    __tcf_0;        .scl    3;      .type   32;     .endef
        .seh_proc       __tcf_0
__tcf_0:
.LFB6829:
        pushq   %rbp
        .seh_pushreg    %rbp
        movq    %rsp, %rbp
        .seh_setframe   %rbp, 0
        subq    $32, %rsp
        .seh_stackalloc 32
        .seh_endprologue
        leaq    _ZStL8__ioinit(%rip), %rcx
        call    _ZNSt8ios_base4InitD1Ev
        nop
        addq    $32, %rsp
        popq    %rbp
        ret
        .seh_endproc
        .def    _Z41__static_initialization_and_destruction_0ii;        .scl    
3;      .type   32;     .endef
        .seh_proc       _Z41__static_initialization_and_destruction_0ii
_Z41__static_initialization_and_destruction_0ii:
.LFB6828:
        pushq   %rbp
        .seh_pushreg    %rbp
        movq    %rsp, %rbp
        .seh_setframe   %rbp, 0
        subq    $32, %rsp
        .seh_stackalloc 32
        .seh_endprologue
        movl    %ecx, 16(%rbp)
        movl    %edx, 24(%rbp)
        cmpl    $1, 16(%rbp)
        jne     .L18
        cmpl    $65535, 24(%rbp)
        jne     .L18
        leaq    _ZStL8__ioinit(%rip), %rcx
        call    _ZNSt8ios_base4InitC1Ev
        leaq    __tcf_0(%rip), %rcx
        call    atexit
.L18:
        nop
        addq    $32, %rsp
        popq    %rbp
        ret
        .seh_endproc
        .def    _GLOBAL__sub_I_main;    .scl    3;      .type   32;     .endef
        .seh_proc       _GLOBAL__sub_I_main
_GLOBAL__sub_I_main:
.LFB6830:
        pushq   %rbp
        .seh_pushreg    %rbp
        movq    %rsp, %rbp
        .seh_setframe   %rbp, 0
        subq    $32, %rsp
        .seh_stackalloc 32
        .seh_endprologue
        movl    $65535, %edx
        movl    $1, %ecx
        call    _Z41__static_initialization_and_destruction_0ii
        nop
        addq    $32, %rsp
        popq    %rbp
        ret
        .seh_endproc
        .section        .ctors,"w"
        .align 8
        .quad   _GLOBAL__sub_I_main
        .ident  "GCC: (Rev2, Built by MSYS2 project) 9.2.0"
        .def    __mingw_wcstod; .scl    2;      .type   32;     .endef
        .def    __mingw_vfprintf;       .scl    2;      .type   32;     .endef
        .def    _Znay;  .scl    2;      .type   32;     .endef
        .def    __cxa_throw_bad_array_new_length;       .scl    2;      .type   
32;     .endef
        .def    _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc;        
.scl    2;      .type   32;     .endef
        .def    _ZNSolsEPFRSoS_E;       .scl    2;      .type   32;     .endef
        .def    _ZdaPv; .scl    2;      .type   32;     .endef
        .def    _ZNSt8ios_base4InitD1Ev;        .scl    2;      .type   32;     
.endef
        .def    _ZNSt8ios_base4InitC1Ev;        .scl    2;      .type   32;     
.endef
        .def    atexit; .scl    2;      .type   32;     .endef
        .section        
.rdata$.refptr._ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, "dr"
        .globl  
.refptr._ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
        .linkonce       discard
.refptr._ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_:
        .quad   _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
        .section        .rdata$.refptr._ZSt4cerr, "dr"
        .globl  .refptr._ZSt4cerr
        .linkonce       discard
.refptr._ZSt4cerr:
        .quad   _ZSt4cerr
#include <windows.h> // This needs to be included or it won't crash, don't ask 
me why
#include <wchar.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#include <iostream>

int main()
{
  size_t num = 5000000;
  auto * buf = new wchar_t[num];
  assert(buf);
  for (size_t i = 0; i < num - 1; ++i) {
    buf[i] = '0';
  }
  buf[num - 1] = 0;

  wchar_t * end = 0;
  std::cerr << "About to call wcstod" << std::endl;
  double d = wcstod(buf, &end);
  printf("If you see this it did not crash, we got %lf\n", d);

  delete[] buf;
  return 0;
}
_______________________________________________
Mingw-w64-public mailing list
Mingw-w64-public@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public

Reply via email to