espeak-ng/espeak-ng-CVE-2023-49990-49991-49992-49993-49994.patch

291 lines
9.2 KiB
Diff
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

commit 58f1e0b6a4e6aa55621c6f01118994d01fd6f68c
Merge: f983e445 e7bcd3cc
Author: Alexander Epaneshnikov <aarnaarn2@gmail.com>
Date: Sun Dec 17 15:29:30 2023 +0300
tests: fix CVE crashes (#1846)
Fixes: #1823, #1824, #1825, #1826, #1827
- Add crash test and vectors provided by @SEU-SSL
- Disallow dummy/null voice load (that causes incorrect translator
initialization)
- Fix empty `phondata` file load (that causes unitialized memory access)
- Limit max word length for RemoveEnding (causes buffer overflow)
- Limit punctlist initialization from embedded commands (buffer
overflow)
- Fix unitialized pitch in wavegen (DBZ and indexing problems)
- Properly zeroize stack variables before use in TranslateClause and
SetWordStress
TODO (in nextup PR): add & fix more vectors from fuzzer.
--- espeak-ng-1.51.1/src/libespeak-ng/dictionary.c
+++ espeak-ng-1.51.1_new/src/libespeak-ng/dictionary.c
@@ -1062,6 +1062,9 @@
static char consonant_types[16] = { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0 };
+ memset(syllable_weight, 0, sizeof(syllable_weight));
+ memset(vowel_length, 0, sizeof(vowel_length));
+
stressflags = tr->langopts.stress_flags;
if (dictionary_flags != NULL)
@@ -3070,6 +3073,7 @@
*word_end = 'e';
}
i = word_end - word;
+ if (i >= N_WORD_BYTES) i = N_WORD_BYTES-1;
if (word_copy != NULL) {
memcpy(word_copy, word, i);
--- espeak-ng-1.51.1/src/libespeak-ng/readclause.c
+++ espeak-ng-1.51.1_new/src/libespeak-ng/readclause.c
@@ -665,7 +665,7 @@
if (c2 != '1') {
// a list of punctuation characters to be spoken, terminated by space
j = 0;
- while (!iswspace(c2) && !Eof()) {
+ while (!Eof() && !iswspace(c2) && (j < N_PUNCTLIST-1)) {
option_punctlist[j++] = c2;
c2 = GetC();
buf[ix++] = ' ';
--- espeak-ng-1.51.1/src/libespeak-ng/synthdata.c
+++ espeak-ng-1.51.1_new/src/libespeak-ng/synthdata.c
@@ -75,8 +75,15 @@
if ((f_in = fopen(buf, "rb")) == NULL)
return create_file_error_context(context, errno, buf);
- if (*ptr != NULL)
+ if (*ptr != NULL) {
free(*ptr);
+ *ptr = NULL;
+ }
+
+ if (length == 0) {
+ *ptr = NULL;
+ return 0;
+ }
if ((*ptr = malloc(length)) == NULL) {
fclose(f_in);
@@ -86,6 +93,7 @@
int error = errno;
fclose(f_in);
free(*ptr);
+ *ptr = NULL;
return create_file_error_context(context, error, buf);
}
@@ -119,9 +127,11 @@
// read the version number and sample rate from the first 8 bytes of phondata
version = 0; // bytes 0-3, version number
rate = 0; // bytes 4-7, sample rate
- for (ix = 0; ix < 4; ix++) {
- version += (wavefile_data[ix] << (ix*8));
- rate += (wavefile_data[ix+4] << (ix*8));
+ if (wavefile_data) {
+ for (ix = 0; ix < 4; ix++) {
+ version += (wavefile_data[ix] << (ix*8));
+ rate += (wavefile_data[ix+4] << (ix*8));
+ }
}
if (version != version_phdata)
--- espeak-ng-1.51.1/src/libespeak-ng/translate.c
+++ espeak-ng-1.51.1_new/src/libespeak-ng/translate.c
@@ -2630,6 +2630,7 @@
if (dict_flags & FLAG_SPELLWORD) {
// redo the word, speaking single letters
for (pw = word; *pw != ' ';) {
+ memset(number_buf, 0, sizeof(number_buf));
memset(number_buf, ' ', 9);
nx = utf8_in(&c_temp, pw);
memcpy(&number_buf[2], pw, nx);
--- espeak-ng-1.51.1/src/libespeak-ng/voices.c
+++ espeak-ng-1.51.1_new/src/libespeak-ng/voices.c
@@ -557,6 +557,10 @@
static char voice_name[40]; // voice name for current_voice_selected
static char voice_languages[100]; // list of languages and priorities for current_voice_selected
+ if ((vname == NULL || vname[0] == 0) && !(control & 8)) {
+ return NULL;
+ }
+
strncpy0(voicename, vname, sizeof(voicename));
if (control & 0x10) {
strcpy(buf, vname);
--- espeak-ng-1.51.1/src/libespeak-ng/wavegen.c
+++ espeak-ng-1.51.1_new/src/libespeak-ng/wavegen.c
@@ -537,14 +537,14 @@
if (wvoice == NULL)
return;
- int x;
+ int x = 0;
int ix;
static int Flutter_ix = 0;
// advance the pitch
wdata.pitch_ix += wdata.pitch_inc;
if ((ix = wdata.pitch_ix>>8) > 127) ix = 127;
- x = wdata.pitch_env[ix] * wdata.pitch_range;
+ if (wdata.pitch_env) x = wdata.pitch_env[ix] * wdata.pitch_range;
wdata.pitch = (x>>8) + wdata.pitch_base;
@@ -1268,6 +1268,10 @@
static bool resume = false;
static int echo_complete = 0;
+
+ if (wdata.pitch < 102400)
+ wdata.pitch = 102400; // min pitch, 25 Hz (25 << 12)
+
while (out_ptr < out_end) {
if (WcmdqUsed() <= 0) {
if (echo_complete > 0) {
--- espeak-ng-1.51.1/tests/CMakeLists.txt
+++ espeak-ng-1.51.1_new/tests/CMakeLists.txt
@@ -0,0 +1,78 @@
+include(CTest)
+
+list(APPEND _binary_tests)
+
+macro(compiled_test _test_name)
+ add_executable(test_${_test_name}
+ $<TARGET_OBJECTS:espeak-ng>
+ ${_test_name}.c
+ )
+ target_link_libraries(test_${_test_name} PRIVATE
+ $<TARGET_PROPERTY:espeak-ng,LINK_LIBRARIES>
+ )
+ target_compile_definitions(test_${_test_name} PRIVATE LIBESPEAK_NG_EXPORT=1)
+ target_include_directories(
+ test_${_test_name} PRIVATE
+ $<TARGET_PROPERTY:espeak-ng,SOURCE_DIR>
+ $<TARGET_PROPERTY:espeak-ng,SOURCE_DIR>/include/compat
+ $<TARGET_PROPERTY:espeak-ng,INTERFACE_INCLUDE_DIRECTORIES>
+ $<TARGET_PROPERTY:espeak-ng-config,INTERFACE_INCLUDE_DIRECTORIES>
+ )
+ if (MINGW)
+ target_link_options(test_${_test_name} PUBLIC "-static" "-static-libstdc++")
+ endif()
+ add_dependencies(test_${_test_name} data)
+ add_test(
+ NAME ${_test_name}
+ COMMAND ${ESPEAK_RUN_ENV} $<TARGET_FILE:test_${_test_name}>
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/..
+ )
+ list(APPEND _binary_tests test_${_test_name})
+endmacro(compiled_test)
+
+find_program(SHELL bash)
+
+macro(shell_test _test_name)
+ add_test(
+ NAME ${_test_name}
+ COMMAND ${ESPEAK_RUN_ENV} ESPEAK_BIN=$<TARGET_FILE:espeak-ng-bin> ${SHELL} ${CMAKE_CURRENT_SOURCE_DIR}/${_test_name}.test
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/..
+ )
+endmacro(shell_test)
+
+compiled_test(api)
+compiled_test(encoding)
+compiled_test(ieee80)
+compiled_test(readclause)
+
+if (SHELL AND UNIX)
+
+shell_test(bom)
+shell_test(non-executable-files-with-executable-bit)
+
+shell_test(cmd_options)
+shell_test(dictionary)
+shell_test(language-numbers-cardinal)
+shell_test(language-numbers-ordinal)
+shell_test(language-phonemes)
+shell_test(language-pronunciation)
+shell_test(language-replace)
+shell_test(ssml)
+shell_test(translate)
+shell_test(variants)
+shell_test(voices)
+shell_test(crash)
+
+# shell_test(windows-data)
+# shell_test(windows-installer)
+
+if (USE_KLATT)
+ shell_test(klatt)
+endif()
+if (USE_MBROLA)
+ shell_test(mbrola)
+endif()
+
+endif()
+
+add_custom_target(tests DEPENDS ${_binary_tests})
--- espeak-ng-1.51.1/tests/crash.test
+++ espeak-ng-1.51.1_new/tests/crash.test
@@ -0,0 +1,17 @@
+#!/bin/sh
+# include common script
+. "`dirname $0`/common"
+
+test_crash() {
+ TEST_NAME=$1
+
+ echo "testing CVE-${TEST_NAME}"
+ ESPEAK_DATA_PATH=`pwd` LD_LIBRARY_PATH=src:${LD_LIBRARY_PATH} \
+ $VALGRIND src/espeak-ng -f "$(dirname $0)/crash_vectors/${TEST_NAME}.txt" -w /dev/null || exit 1
+}
+
+test_crash cve-2023-49990
+test_crash cve-2023-49991
+test_crash cve-2023-49992
+test_crash cve-2023-49993
+test_crash cve-2023-49994
--- espeak-ng-1.51.1/tests/crash_vectors/cve-2023-49990.txt
+++ espeak-ng-1.51.1_new/tests/crash_vectors/cve-2023-49990.txt
@@ -0,0 +1 @@
+<2B><><EFBFBD><EFBFBD>V<><56><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>V
<EFBFBD><EFBFBD>V<><07><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>s<><73><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>s<EFBFBD><73><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>eeeeeeeeseee<65><65><EFBFBD><EFBFBD><EFBFBD>
\ 文件末尾没有换行符
--- espeak-ng-1.51.1/tests/crash_vectors/cve-2023-49991.txt
+++ espeak-ng-1.51.1_new/tests/crash_vectors/cve-2023-49991.txt
@@ -0,0 +1 @@
+<2B><>V<>
<EFBFBD><EFBFBD>V<><56>h<EFBFBD><68><EFBFBD><EFBFBD><EFBFBD>VD<56>Z<EFBFBD><5A><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><ECBBBB>־<EFBFBD><D6BE><EFBFBD><EFBFBD><EFBFBD>ִ<EFBFBD><D6B4>ֻ<EFBFBD><D6BB><EFBFBD><EFBFBD><08><>ֻ<EFBFBD><D6BB><EFBFBD>ժ<EFBFBD><D5AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>`v
\ 文件末尾没有换行符
--- espeak-ng-1.51.1/tests/crash_vectors/cve-2023-49992.txt
+++ espeak-ng-1.51.1_new/tests/crash_vectors/cve-2023-49992.txt
@@ -0,0 +1 @@
+<2B><><EFBFBD><EFBFBD><EFBFBD><03>!<21><><EFBFBD><EFBFBD><EFBFBD>bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbIbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb<62> !<00><18><><EFBFBD>
\ 文件末尾没有换行符
--- espeak-ng-1.51.1/tests/crash_vectors/cve-2023-49993.txt
+++ espeak-ng-1.51.1_new/tests/crash_vectors/cve-2023-49993.txt
@@ -0,0 +1,5 @@
+hV
+$
+V
+$
+B:\\lA:\@\<5C>\<5C>\H<>\\<5C>???T??%?\<5C>\<5C>\\<5C>\000000000000000000000000000000000000000000000000000000000@000000000000000000000000000000??0$? <09>#???<14> ?-0?<0F>000000L00<30>??<3F>?\H<>\\<5C>???T?? ?\<5C>\<5C>\\<5C>\<>\u\D:\@\000L00<30>?<3F>\<5C>\H<>\\<5C>???T??%?\<5C>\<5C>\\<5C>\0000000000000000200000000000000000000000000000000000000000000000000000000??0$? ? <09>????<14> ?-0?-<2D>00000L00<30>???000E+0%!!?
\ 文件末尾没有换行符
--- espeak-ng-1.51.1/tests/crash_vectors/cve-2023-49994.txt
+++ espeak-ng-1.51.1_new/tests/crash_vectors/cve-2023-49994.txt
@@ -0,0 +1 @@
+"[[-#,- -1-2.
r--<2D>#--O)C--!<21>E-1<>@5-!-V-1--
\ 文件末尾没有换行符