mmorise / World

A high-quality speech analysis, manipulation and synthesis system
http://www.kisc.meiji.ac.jp/~mmorise/world/english
Other
1.15k stars 249 forks source link

Heap buffer overflow in cheaptrick #127

Closed taroushirani closed 2 years ago

taroushirani commented 2 years ago

Hello. I met the heap buffer overflow in cheaptrick when I used World via pyworld(version 0.3.0, built with -fsanitize=address option).

=================================================================
==19501==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x61d004a05e80 at pc 0x7fa5bb051a16 bp 0x7fffdcefdc30 sp 0x7fffdcefdc28
WRITE of size 8 at 0x61d004a05e80 thread T0
    #0 0x7fa5bb051a15 in GetWindowedWaveform lib/World/src/cheaptrick.cpp:127
    #1 0x7fa5bb051a15 in CheapTrickGeneralBody lib/World/src/cheaptrick.cpp:164
    #2 0x7fa5bb051a15 in CheapTrick lib/World/src/cheaptrick.cpp:218
    #3 0x7fa5bb04d744 in __pyx_pf_7pyworld_7pyworld_10cheaptrick pyworld/pyworld.cpp:4843
    #4 0x7fa5bb04f8c4 in __pyx_pw_7pyworld_7pyworld_11cheaptrick pyworld/pyworld.cpp:4444
    #5 0x5d8984 in _PyMethodDef_RawFastCallKeywords (/usr/bin/python3.7+0x5d8984)
    #6 0x54b32f  (/usr/bin/python3.7+0x54b32f)
    #7 0x54f45d in _PyEval_EvalFrameDefault (/usr/bin/python3.7+0x54f45d)
    #8 0x5da535 in _PyFunction_FastCallDict (/usr/bin/python3.7+0x5da535)
    #9 0x4d97e1  (/usr/bin/python3.7+0x4d97e1)
    #10 0x5dc4f5 in PyObject_Call (/usr/bin/python3.7+0x5dc4f5)
    #11 0x54f986 in _PyEval_EvalFrameDefault (/usr/bin/python3.7+0x54f986)
    #12 0x5d91fb in _PyFunction_FastCallKeywords (/usr/bin/python3.7+0x5d91fb)
    #13 0x54e7df in _PyEval_EvalFrameDefault (/usr/bin/python3.7+0x54e7df)
    #14 0x54c327 in _PyEval_EvalCodeWithName (/usr/bin/python3.7+0x54c327)
    #15 0x5da6fd in _PyFunction_FastCallDict (/usr/bin/python3.7+0x5da6fd)
    #16 0x590109  (/usr/bin/python3.7+0x590109)
    #17 0x4e3e28 in PyObject_GetItem (/usr/bin/python3.7+0x4e3e28)
    #18 0x54ea09 in _PyEval_EvalFrameDefault (/usr/bin/python3.7+0x54ea09)
    #19 0x5d91fb in _PyFunction_FastCallKeywords (/usr/bin/python3.7+0x5d91fb)
    #20 0x54e5ab in _PyEval_EvalFrameDefault (/usr/bin/python3.7+0x54e5ab)
    #21 0x54bcc1 in _PyEval_EvalCodeWithName (/usr/bin/python3.7+0x54bcc1)
    #22 0x5d94f1 in _PyFunction_FastCallKeywords (/usr/bin/python3.7+0x5d94f1)
    #23 0x54b1ef  (/usr/bin/python3.7+0x54b1ef)
    #24 0x54f45d in _PyEval_EvalFrameDefault (/usr/bin/python3.7+0x54f45d)
    #25 0x54bcc1 in _PyEval_EvalCodeWithName (/usr/bin/python3.7+0x54bcc1)
    #26 0x5d94f1 in _PyFunction_FastCallKeywords (/usr/bin/python3.7+0x5d94f1)
    #27 0x54b1ef  (/usr/bin/python3.7+0x54b1ef)
    #28 0x54f45d in _PyEval_EvalFrameDefault (/usr/bin/python3.7+0x54f45d)
    #29 0x54c327 in _PyEval_EvalCodeWithName (/usr/bin/python3.7+0x54c327)
    #30 0x5d94f1 in _PyFunction_FastCallKeywords (/usr/bin/python3.7+0x5d94f1)
    #31 0x54e5ab in _PyEval_EvalFrameDefault (/usr/bin/python3.7+0x54e5ab)
    #32 0x5d91fb in _PyFunction_FastCallKeywords (/usr/bin/python3.7+0x5d91fb)
    #33 0x54e5ab in _PyEval_EvalFrameDefault (/usr/bin/python3.7+0x54e5ab)
    #34 0x54c327 in _PyEval_EvalCodeWithName (/usr/bin/python3.7+0x54c327)
    #35 0x5d94f1 in _PyFunction_FastCallKeywords (/usr/bin/python3.7+0x5d94f1)
    #36 0x54b1ef  (/usr/bin/python3.7+0x54b1ef)
    #37 0x54f45d in _PyEval_EvalFrameDefault (/usr/bin/python3.7+0x54f45d)
    #38 0x54c327 in _PyEval_EvalCodeWithName (/usr/bin/python3.7+0x54c327)
    #39 0x5d94f1 in _PyFunction_FastCallKeywords (/usr/bin/python3.7+0x5d94f1)
    #40 0x54e5ab in _PyEval_EvalFrameDefault (/usr/bin/python3.7+0x54e5ab)
    #41 0x5d91fb in _PyFunction_FastCallKeywords (/usr/bin/python3.7+0x5d91fb)
    #42 0x54e5ab in _PyEval_EvalFrameDefault (/usr/bin/python3.7+0x54e5ab)
    #43 0x54bcc1 in _PyEval_EvalCodeWithName (/usr/bin/python3.7+0x54bcc1)
    #44 0x54e0a2 in PyEval_EvalCode (/usr/bin/python3.7+0x54e0a2)
    #45 0x630ce1  (/usr/bin/python3.7+0x630ce1)
    #46 0x630d96 in PyRun_FileExFlags (/usr/bin/python3.7+0x630d96)
    #47 0x6319fe in PyRun_SimpleFileExFlags (/usr/bin/python3.7+0x6319fe)
    #48 0x65432d  (/usr/bin/python3.7+0x65432d)
    #49 0x65468d in _Py_UnixMain (/usr/bin/python3.7+0x65468d)
    #50 0x7fa5c1a3409a in __libc_start_main ../csu/libc-start.c:308
    #51 0x5e0e89 in _start (/usr/bin/python3.7+0x5e0e89)

0x61d004a05e80 is located 0 bytes to the right of 2048-byte region [0x61d004a05680,0x61d004a05e80)
allocated by thread T0 here:
    #0 0x7fa5c215aef0 in operator new[](unsigned long) (/usr/lib/x86_64-linux-gnu/libasan.so.5+0xeaef0)
    #1 0x7fa5bb054295 in InitializeForwardRealFFT lib/World/src/common.cpp:127

SUMMARY: AddressSanitizer: heap-buffer-overflow lib/World/src/cheaptrick.cpp:127 in GetWindowedWaveform
Shadow bytes around the buggy address:
  0x0c3a80938b80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c3a80938b90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c3a80938ba0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c3a80938bb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c3a80938bc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c3a80938bd0:[fa]fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c3a80938be0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c3a80938bf0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c3a80938c00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c3a80938c10: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c3a80938c20: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==19501==ABORTING

In GetWindowedWaveform in cheaptrick.cpp, waveform is ForwardRealFFT.waveform and its size is ForwardRealFFT.fft_size. If half_window_length is bigger than (ForwardRealFFT.fft_size -1 )/ 2, the access by index at line 127 of cheaptrick.cpp may result in heap buffer overflow.

Is there any need to check half_window_length is smaller than (ForwardRealFFT.fft_size -1 )/ 2?

mmorise commented 2 years ago

Thank you for your comment.

This error may be caused when an F0 in a frame is under the world::kFloorF0 (71 Hz). We have already modified this problem by adding a safeguard by line 217 in the CheapTrick.cpp, but the pyworld may not include this modification. You can also avoid this problem by directly setting the fft_size to an appropriate value. If you can't solve this problem with this modification, please get in touch with me again.

taroushirani commented 2 years ago

Thank you for your rapid response.

I built pyworld with the latest World source code via git, and I used fft_size calculated by GetFFTSizeForCheapTrick (because pyworld uses GetFFTSizeForCheapTrick to set fft_size by default). I'm not sure but an inadequate value of f0_floor may result in this phenomenon.

As for now, cutting the length of half_window_length to "(forward_real_fft->fft_size -1) / 2" seems to work fine. Thank you

mmorise commented 2 years ago

I think that your approach can work well when the F0 in the frame is above f0_floor. If you want to guarantee the performance of the spectral envelope, I recommend setting the fft_size manually based on the minimum value of F0 contour estimated by Dio() or Harvest().

If you want to keep the current fft_size irrespective of the lower F0 value than the lower limit, your approach seems to be reasonable.