[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#1059656: marked as done (bookworm-pu: package espeak-ng/1.51+dfsg-10+deb12u1)



Your message dated Sat, 10 Feb 2024 13:11:20 +0000
with message-id <E1rYn8a-002ya7-G2@coccia.debian.org>
and subject line Released with 12.5
has caused the Debian Bug report #1059656,
regarding bookworm-pu: package espeak-ng/1.51+dfsg-10+deb12u1
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact owner@bugs.debian.org
immediately.)


-- 
1059656: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1059656
Debian Bug Tracking System
Contact owner@bugs.debian.org with problems
--- Begin Message ---
Package: release.debian.org
Severity: normal
Tags: bookworm
User: release.debian.org@packages.debian.org
Usertags: pu
X-Debbugs-Cc: espeak-ng@packages.debian.org
Control: affects -1 + src:espeak-ng

[ Reason ]
This upload provides fixes for CVEs. They are not a regression over
oldstable.

[ Impact ]
Blind users using the espeak-ng speech synthesis might be at risk when
e.g. reading a webpage that contains the CVE triggers.

[ Tests ]
CVE tests are getting added in the patch.

[ Risks ]
The code is relatively simple, comes from upstream, and has been in
testing since December 24th.

[ Checklist ]
  [X] *all* changes are documented in the d/changelog
  [X] I reviewed all changes and I approve them
  [X] attach debdiff against the package in (old)stable
  [X] the issue is verified as fixed in unstable

[ Change s]in *all* the changes)

The changes fix various use-after-free, unitialized buffers (which lead
to missing \0 terminators), and missing buffer bound checks.
diff -Nru espeak-ng-1.51+dfsg/debian/changelog espeak-ng-1.51+dfsg/debian/changelog
--- espeak-ng-1.51+dfsg/debian/changelog	2023-01-26 01:09:47.000000000 +0100
+++ espeak-ng-1.51+dfsg/debian/changelog	2023-12-21 01:26:02.000000000 +0100
@@ -1,3 +1,10 @@
+espeak-ng (1.51+dfsg-10+deb12u1) bookworm; urgency=medium
+
+  * patches/CVE: Fix CVE-2023-49990, CVE-2023-49991, CVE-2023-49992,
+    CVE-2023-49993, CVE-2023-49994 (Closes: Bug#1059060)
+
+ -- Samuel Thibault <sthibault@debian.org>  Thu, 21 Dec 2023 01:26:02 +0100
+
 espeak-ng (1.51+dfsg-10) unstable; urgency=medium
 
   * watch: Use API instead of releases page.
diff -Nru espeak-ng-1.51+dfsg/debian/patches/CVE espeak-ng-1.51+dfsg/debian/patches/CVE
--- espeak-ng-1.51+dfsg/debian/patches/CVE	1970-01-01 01:00:00.000000000 +0100
+++ espeak-ng-1.51+dfsg/debian/patches/CVE	2023-12-21 01:26:02.000000000 +0100
@@ -0,0 +1,326 @@
+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.
+
+commit 9decedb8c229e1a4219baceaab7a3d656e889e31
+Author: Samuel Thibault <samuel.thibault@ens-lyon.org>
+Date:   Thu Jun 30 00:50:18 2022 +0200
+
+    Fix missing checks for EOF
+
+commit c4c05820c4a47369d5a81e4a506fe7abb2fa7ed6
+Author: Yury Popov <git@phoenix.dj>
+Date:   Sat Dec 16 19:24:51 2023 +0300
+
+    tests: add CVE crash vectors
+
+commit e79405772cecf47053116aeaad10e64606292b14
+Author: Yury Popov <git@phoenix.dj>
+Date:   Sat Dec 16 23:55:03 2023 +0300
+
+    voices: disallow dummy voice when not compiling
+
+commit 7d4ad3c2ae063cb08bfd606021bc323dfbadaba9
+Author: Yury Popov <git@phoenix.dj>
+Date:   Sat Dec 16 21:50:07 2023 +0300
+
+    synthdata: fix empty file load
+
+commit b99f332c576eb49839613a55cfd3e0e1b5487191
+Author: Yury Popov <git@phoenix.dj>
+Date:   Sat Dec 16 22:45:15 2023 +0300
+
+    dictionary: limit word length
+
+commit 1a7ecfc2f202438b17e742368f910e6099ce02b7
+Author: Yury Popov <git@phoenix.dj>
+Date:   Sat Dec 16 22:50:01 2023 +0300
+
+    readclause: limit embedded punctlist length
+
+commit a5eb246debb51ba328ef399350dfcd5d87782245
+Author: Yury Popov <git@phoenix.dj>
+Date:   Sat Dec 16 23:03:16 2023 +0300
+
+    wavegen: fix unitialized pitch
+
+commit 5f7db763e2eff1d8174d2b65a4bbe4b2a85c8a0c
+Author: Yury Popov <git@phoenix.dj>
+Date:   Sat Dec 16 23:17:45 2023 +0300
+
+    translate: fix number_buf initialization
+
+commit e7bcd3cc1599ebb531bb62fc3007d3ce1dade167
+Author: Yury Popov <git@phoenix.dj>
+Date:   Sat Dec 16 23:26:07 2023 +0300
+
+    dictionary: fix stack initialization
+
+---
+ src/libespeak-ng/dictionary.c          |    4 ++++
+ src/libespeak-ng/readclause.c          |   12 ++++++------
+ src/libespeak-ng/synthdata.c           |   18 ++++++++++++++----
+ src/libespeak-ng/translate.c           |    1 +
+ src/libespeak-ng/voices.c              |   20 ++++++++++++--------
+ src/libespeak-ng/wavegen.c             |    9 ++++++---
+ tests/crash.test                       |   17 +++++++++++++++++
+ tests/crash_vectors/cve-2023-49990.txt |    1 +
+ tests/crash_vectors/cve-2023-49991.txt |    1 +
+ tests/crash_vectors/cve-2023-49994.txt |    1 +
+ 10 files changed, 63 insertions(+), 21 deletions(-)
+
+--- a/src/libespeak-ng/readclause.c
++++ b/src/libespeak-ng/readclause.c
+@@ -335,7 +335,7 @@ static int AnnouncePunctuation(Translato
+ 
+ 		if ((*bufix == 0) || (end_clause == 0) || (tr->langopts.param[LOPT_ANNOUNCE_PUNCT] & 2)) {
+ 			punct_count = 1;
+-			while ((c2 == c1) && (c1 != '<')) { // don't eat extra '<', it can miss XML tags
++			while (!Eof() && (c2 == c1) && (c1 != '<')) { // don't eat extra '<', it can miss XML tags
+ 				punct_count++;
+ 				c2 = GetC();
+ 			}
+@@ -647,7 +647,7 @@ int ReadClause(Translator *tr, char *buf
+  			// an embedded command. If it's a voice change, end the clause
+ 			if (c2 == 'V') {
+ 				buf[ix++] = 0; // end the clause at this point
+-				while (!iswspace(c1 = GetC()) && !Eof() && (ix < (n_buf-1)))
++				while (!Eof() && !iswspace(c1 = GetC()) && (ix < (n_buf-1)))
+ 					buf[ix++] = c1; // add voice name to end of buffer, after the text
+ 				buf[ix++] = 0;
+ 				return CLAUSE_VOICE;
+@@ -657,7 +657,7 @@ int ReadClause(Translator *tr, char *buf
+ 				strcpy(&buf[ix], "   ");
+ 				ix += 3;
+ 
+-				if ((c2 = GetC()) == '0')
++				if (!Eof() && (c2 = GetC()) == '0')
+ 					option_punctuation = 0;
+ 				else {
+ 					option_punctuation = 1;
+@@ -665,7 +665,7 @@ int ReadClause(Translator *tr, char *buf
+ 					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++] = ' ';
+@@ -791,7 +791,7 @@ int ReadClause(Translator *tr, char *buf
+ 			}
+ 
+ 			if ((c1 == '.') && (c2 == '.')) {
+-				while ((c_next = GetC()) == '.') {
++				while (!Eof() && (c_next = GetC()) == '.') {
+ 					// 3 or more dots, replace by elipsis
+ 					c1 = 0x2026;
+ 					c2 = ' ';
+@@ -808,7 +808,7 @@ int ReadClause(Translator *tr, char *buf
+ 				// Handling of sequences of ? and ! like ??!?, !!??!, ?!! etc
+ 				// Use only first char as determinant
+ 				if(punct_data & (CLAUSE_QUESTION | CLAUSE_EXCLAMATION)) {
+-					while(clause_type_from_codepoint(c2) & (CLAUSE_QUESTION | CLAUSE_EXCLAMATION)) {
++					while(!Eof() && clause_type_from_codepoint(c2) & (CLAUSE_QUESTION | CLAUSE_EXCLAMATION)) {
+ 						c_next = GetC();
+ 						c2 = c_next;
+ 					}
+--- /dev/null
++++ b/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
+--- /dev/null
++++ b/tests/crash_vectors/cve-2023-49990.txt
+@@ -0,0 +1 @@
++��V�
��V
��V���������s���eeeeeeeeseee��
+\ No newline at end of file
+--- /dev/null
++++ b/tests/crash_vectors/cve-2023-49991.txt
+@@ -0,0 +1 @@
++��V�V��D��������컻��־�����ֻ��������ժ������
+\ No newline at end of file
+--- /dev/null
++++ b/tests/crash_vectors/cve-2023-49994.txt
+@@ -0,0 +1 @@
++"[[-#,-	-1-2.
r--�#--O)C--!�E-1�@5-!-V-1--
+\ No newline at end of file
+--- a/src/libespeak-ng/voices.c
++++ b/src/libespeak-ng/voices.c
+@@ -554,6 +554,10 @@ voice_t *LoadVoice(const char *vname, in
+ 	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);
+@@ -937,14 +941,14 @@ voice_t *LoadVoice(const char *vname, in
+ 
+ 	if (!tone_only) {
+ 		if (!!(control & 8/*compiling phonemes*/)) {
+-                        /* Set by espeak_ng_CompilePhonemeDataPath when it
+-                         * calls LoadVoice("", 8) to set up a dummy(?) voice.
+-                         * As phontab may not yet exist this avoids the spurious
+-                         * error message and guarantees consistent results by
+-                         * not actually reading a potentially bogus phontab...
+-                         */
+-                        ix = 0;
+-                } else if ((ix = SelectPhonemeTableName(phonemes_name)) < 0) {
++			/* Set by espeak_ng_CompilePhonemeDataPath when it
++				* calls LoadVoice("", 8) to set up a dummy(?) voice.
++				* As phontab may not yet exist this avoids the spurious
++				* error message and guarantees consistent results by
++				* not actually reading a potentially bogus phontab...
++				*/
++			ix = 0;
++		} else if ((ix = SelectPhonemeTableName(phonemes_name)) < 0) {
+ 			fprintf(stderr, "Unknown phoneme table: '%s'\n", phonemes_name);
+ 			ix = 0;
+ 		}
+--- a/src/libespeak-ng/synthdata.c
++++ b/src/libespeak-ng/synthdata.c
+@@ -75,8 +75,15 @@ static espeak_ng_STATUS ReadPhFile(void
+ 	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 @@ static espeak_ng_STATUS ReadPhFile(void
+ 		int error = errno;
+ 		fclose(f_in);
+ 		free(*ptr);
++		*ptr = NULL;
+ 		return create_file_error_context(context, error, buf);
+ 	}
+ 
+@@ -119,9 +127,11 @@ espeak_ng_STATUS LoadPhData(int *srate,
+ 	// 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)
+--- a/src/libespeak-ng/dictionary.c
++++ b/src/libespeak-ng/dictionary.c
+@@ -1062,6 +1062,9 @@ void SetWordStress(Translator *tr, char
+ 
+ 	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 @@ int RemoveEnding(Translator *tr, char *w
+ 			*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);
+--- a/src/libespeak-ng/wavegen.c
++++ b/src/libespeak-ng/wavegen.c
+@@ -537,14 +537,14 @@ static void AdvanceParameters()
+ 	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;
+ 	
+ 	
+@@ -560,7 +560,7 @@ static void AdvanceParameters()
+ 	
+ 	if(const_f0)
+ 		wdata.pitch = (const_f0<<12);
+-	
++
+ 	if (wdata.pitch < 102400)
+ 		wdata.pitch = 102400; // min pitch, 25 Hz  (25 << 12)
+ 
+@@ -1268,6 +1268,9 @@ static int WavegenFill2()
+ 	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) {
+--- a/src/libespeak-ng/translate.c
++++ b/src/libespeak-ng/translate.c
+@@ -2630,6 +2630,7 @@ void TranslateClause(Translator *tr, int
+ 			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);
diff -Nru espeak-ng-1.51+dfsg/debian/patches/series espeak-ng-1.51+dfsg/debian/patches/series
--- espeak-ng-1.51+dfsg/debian/patches/series	2022-09-23 00:13:40.000000000 +0200
+++ espeak-ng-1.51+dfsg/debian/patches/series	2023-12-21 01:26:02.000000000 +0100
@@ -9,3 +9,4 @@
 lang
 long-build-path
 mb-fr
+CVE
diff -Nru espeak-ng-1.51+dfsg/debian/salsa-ci.yml espeak-ng-1.51+dfsg/debian/salsa-ci.yml
--- espeak-ng-1.51+dfsg/debian/salsa-ci.yml	2022-09-23 01:53:17.000000000 +0200
+++ espeak-ng-1.51+dfsg/debian/salsa-ci.yml	2023-12-21 01:26:02.000000000 +0100
@@ -5,6 +5,8 @@
 
 # needs building a host espeak-ng to generate the phoneme databases
 variables:
+  RELEASE: bookworm
+
   SALSA_CI_DISABLE_CROSSBUILD_ARM64: '1'
 
   SALSA_CI_REPROTEST_ENABLE_DIFFOSCOPE: 1

--- End Message ---
--- Begin Message ---
Version: 12.5

The upload requested in this bug has been released as part of 12.5.

--- End Message ---

Reply to: