mirror of
https://github.com/openembedded/meta-openembedded.git
synced 2026-10-14 18:07:06 +00:00
tesseract: patch CVE-2026-88052
Details:
https://nvd.nist.gov/vuln/detail/cve-2026-88052
(cherry picked from commit 251dd7f80d)
Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
Signed-off-by: Anuj Mittal <anuj.mittal@oss.qualcomm.com>
Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
Signed-off-by: Khem Raj <khem.raj@oss.qualcomm.com>
This commit is contained in:
1 parent
bf39596278
commit
8ee82e432c
2 files changed
+168
-2
No files matched your search
@@ -0,0 +1,165 @@
|
||||
From c60ad589ff3a645a3fdf13cb24fe719313145a06 Mon Sep 17 00:00:00 2001
|
||||
From: Stefan Weil <sw@weilnetz.de>
|
||||
Date: Fri, 21 Aug 2026 18:34:33 +0200
|
||||
Subject: [PATCH] Reject unicharset files whose inserts desync id from unichars
|
||||
|
||||
UNICHARSET::load_via_fgets reads the unichar count via sscanf and
|
||||
trusts it as the loop bound, indexing the unichars vector with the
|
||||
loop index id via the unchecked set_* accessors. unichar_insert is a
|
||||
no-op for duplicate (or empty) representations, so once any insert
|
||||
no-ops, unichars.size() falls behind id and the subsequent
|
||||
set_*(id, ...) and unichars[id].properties writes land past the end
|
||||
of the vector - a deterministic heap out-of-bounds write (including a
|
||||
std::string assignment via set_normed) for every remaining line, on
|
||||
both the LSTM and legacy init paths. A malformed unicharset with a
|
||||
duplicate line (e.g. two identical entries) triggers it; a
|
||||
non-positive header count likewise loads an empty unicharset
|
||||
"successfully".
|
||||
|
||||
Key changes:
|
||||
- unicharset.cpp: reject unicharset_size <= 0, and after each insert
|
||||
verify the vector actually grew to id + 1; on mismatch report the
|
||||
offending line and reject the file instead of writing out of bounds.
|
||||
- unittest: add unicharset_load_test with a duplicate-representation
|
||||
unicharset (on unpatched code the test dies on the
|
||||
container-overflow in load_via_fgets), a zero and a negative count,
|
||||
and a positive control that a valid unicharset still loads.
|
||||
|
||||
Reported-by: Zhixi "Jace" Sun <g.mygenie@gmail.com>
|
||||
Assisted-by: OpenCode / qwen3.8-27b-thinking (Alibaba Cloud)
|
||||
Signed-off-by: Stefan Weil <sw@weilnetz.de>
|
||||
(cherry picked from commit 2d04d640db2e8c7e3bab2369d599343b5a8b8443)
|
||||
|
||||
CVE: CVE-2026-88052
|
||||
Upstream-Status: Backport [https://github.com/tesseract-ocr/tesseract/commit/2d04d640db2e8c7e3bab2369d599343b5a8b8443]
|
||||
Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
|
||||
---
|
||||
Makefile.am | 5 +++
|
||||
src/ccutil/unicharset.cpp | 12 ++++++
|
||||
unittest/unicharset_load_test.cc | 64 ++++++++++++++++++++++++++++++++
|
||||
3 files changed, 81 insertions(+)
|
||||
create mode 100644 unittest/unicharset_load_test.cc
|
||||
|
||||
diff --git a/Makefile.am b/Makefile.am
|
||||
index bec9ab0e..22c2c7a0 100644
|
||||
--- a/Makefile.am
|
||||
+++ b/Makefile.am
|
||||
@@ -1220,6 +1220,7 @@ check_PROGRAMS += tfile_test
|
||||
if ENABLE_TRAINING
|
||||
check_PROGRAMS += unichar_test
|
||||
check_PROGRAMS += unicharcompress_test
|
||||
+check_PROGRAMS += unicharset_load_test
|
||||
check_PROGRAMS += unicharset_test
|
||||
check_PROGRAMS += validate_grapheme_test
|
||||
check_PROGRAMS += validate_indic_test
|
||||
@@ -1493,6 +1494,10 @@ unicharcompress_test_SOURCES = unittest/unicharcompress_test.cc
|
||||
unicharcompress_test_CPPFLAGS = $(unittest_CPPFLAGS)
|
||||
unicharcompress_test_LDADD = $(TRAINING_LIBS) $(ICU_UC_LIBS)
|
||||
|
||||
+unicharset_load_test_SOURCES = unittest/unicharset_load_test.cc
|
||||
+unicharset_load_test_CPPFLAGS = $(unittest_CPPFLAGS)
|
||||
+unicharset_load_test_LDADD = $(TESS_LIBS)
|
||||
+
|
||||
unicharset_test_SOURCES = unittest/unicharset_test.cc
|
||||
unicharset_test_CPPFLAGS = $(unittest_CPPFLAGS)
|
||||
unicharset_test_LDADD = $(TRAINING_LIBS) $(ICU_UC_LIBS)
|
||||
diff --git a/src/ccutil/unicharset.cpp b/src/ccutil/unicharset.cpp
|
||||
index b29ec3b7..0e72ae48 100644
|
||||
--- a/src/ccutil/unicharset.cpp
|
||||
+++ b/src/ccutil/unicharset.cpp
|
||||
@@ -791,6 +791,9 @@ bool UNICHARSET::load_via_fgets(
|
||||
sscanf(buffer, "%d", &unicharset_size) != 1) {
|
||||
return false;
|
||||
}
|
||||
+ if (unicharset_size <= 0) {
|
||||
+ return false;
|
||||
+ }
|
||||
for (UNICHAR_ID id = 0; id < unicharset_size; ++id) {
|
||||
char unichar[256];
|
||||
unsigned int properties;
|
||||
@@ -884,6 +887,15 @@ bool UNICHARSET::load_via_fgets(
|
||||
} else {
|
||||
this->unichar_insert_backwards_compatible(unichar);
|
||||
}
|
||||
+ // A duplicate or empty representation makes the insert a no-op,
|
||||
+ // desynchronizing id from the unichars vector; the set_* calls and
|
||||
+ // unichars[id] below would then write out of bounds. The file is
|
||||
+ // malformed, so reject it.
|
||||
+ if (size() != static_cast<size_t>(id) + 1) {
|
||||
+ fprintf(stderr, "%s:%d unichar %d has a duplicate or empty representation\n",
|
||||
+ __FILE__, __LINE__, id);
|
||||
+ return false;
|
||||
+ }
|
||||
|
||||
this->set_isalpha(id, properties & ISALPHA_MASK);
|
||||
this->set_islower(id, properties & ISLOWER_MASK);
|
||||
diff --git a/unittest/unicharset_load_test.cc b/unittest/unicharset_load_test.cc
|
||||
new file mode 100644
|
||||
index 00000000..d775e233
|
||||
--- /dev/null
|
||||
+++ b/unittest/unicharset_load_test.cc
|
||||
@@ -0,0 +1,64 @@
|
||||
+///////////////////////////////////////////////////////////////////////
|
||||
+// File: unicharset_load_test.cc
|
||||
+// Description: Tests that UNICHARSET::load_via_fgets rejects unicharset
|
||||
+// files whose insertions desynchronize the id loop index
|
||||
+// from the unichars vector (duplicate or empty
|
||||
+// representations), which would make the subsequent set_*
|
||||
+// calls write out of bounds, and non-positive size counts.
|
||||
+//
|
||||
+// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
+// you may not use this file except in compliance with the License.
|
||||
+// You may obtain a copy of the License at
|
||||
+// http://www.apache.org/licenses/LICENSE-2.0
|
||||
+//
|
||||
+///////////////////////////////////////////////////////////////////////
|
||||
+
|
||||
+#include "include_gunit.h"
|
||||
+
|
||||
+#include "serialis.h" // for TFile
|
||||
+#include "unicharset.h"
|
||||
+
|
||||
+#include <cstring>
|
||||
+
|
||||
+namespace tesseract {
|
||||
+namespace {
|
||||
+
|
||||
+// Loads the given unicharset text via the TFile-based loader.
|
||||
+bool LoadUnicharset(const char *text, UNICHARSET *unicharset) {
|
||||
+ TFile fp;
|
||||
+ if (!fp.Open(text, std::strlen(text))) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ return unicharset->load_from_file(&fp, false);
|
||||
+}
|
||||
+
|
||||
+// A duplicate representation makes the second insert a no-op, so on
|
||||
+// unpatched code the set_* calls for the remaining lines write past
|
||||
+// the end of the unichars vector (ASan container-overflow).
|
||||
+TEST(UnicharsetLoadTest, RejectsDuplicateRepresentation) {
|
||||
+ const char *text = "3\nA 0 Latin\nA 0 Latin\nB 0 Latin\n";
|
||||
+ UNICHARSET unicharset;
|
||||
+ EXPECT_FALSE(LoadUnicharset(text, &unicharset));
|
||||
+}
|
||||
+
|
||||
+// A non-positive size count must be rejected; on unpatched code a
|
||||
+// zero or negative count loads an empty unicharset successfully.
|
||||
+TEST(UnicharsetLoadTest, RejectsNonPositiveCount) {
|
||||
+ const char *texts[] = {"0\n", "-1\n"};
|
||||
+ for (const char *text : texts) {
|
||||
+ UNICHARSET unicharset;
|
||||
+ EXPECT_FALSE(LoadUnicharset(text, &unicharset));
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+// A valid unicharset must still be accepted.
|
||||
+TEST(UnicharsetLoadTest, AcceptsValidUnicharset) {
|
||||
+ const char *text = "3\nA 0 Latin\nB 0 Latin\nC 0 Latin\n";
|
||||
+ UNICHARSET unicharset;
|
||||
+ ASSERT_TRUE(LoadUnicharset(text, &unicharset));
|
||||
+ EXPECT_EQ(unicharset.size(), 3u);
|
||||
+ EXPECT_STREQ(unicharset.id_to_unichar(1), "B");
|
||||
+}
|
||||
+
|
||||
+} // namespace
|
||||
+} // namespace tesseract
|
||||
@@ -6,8 +6,9 @@ LICENSE = "Apache-2.0"
|
||||
LIC_FILES_CHKSUM = "file://LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57"
|
||||
|
||||
SRCREV = "db0ec62f81b0737fbbe184d8fea40af5738f8eef"
|
||||
SRC_URI = "git://github.com/${BPN}-ocr/${BPN}.git;branch=main;protocol=https;tag=${PV}"
|
||||
|
||||
SRC_URI = "git://github.com/${BPN}-ocr/${BPN}.git;branch=main;protocol=https;tag=${PV} \
|
||||
file://CVE-2026-88052.patch \
|
||||
"
|
||||
|
||||
DEPENDS = "leptonica"
|
||||
|
||||
|
||||
Reference in new issue
Block a user