summaryrefslogtreecommitdiffstats
path: root/meta/recipes-graphics/harfbuzz/harfbuzz/CVE-2023-25193.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta/recipes-graphics/harfbuzz/harfbuzz/CVE-2023-25193.patch')
-rw-r--r--meta/recipes-graphics/harfbuzz/harfbuzz/CVE-2023-25193.patch179
1 files changed, 179 insertions, 0 deletions
diff --git a/meta/recipes-graphics/harfbuzz/harfbuzz/CVE-2023-25193.patch b/meta/recipes-graphics/harfbuzz/harfbuzz/CVE-2023-25193.patch
new file mode 100644
index 0000000000..e4ac13dbad
--- /dev/null
+++ b/meta/recipes-graphics/harfbuzz/harfbuzz/CVE-2023-25193.patch
@@ -0,0 +1,179 @@
1From 9c8e972dbecda93546038d24444d8216397d75a3 Mon Sep 17 00:00:00 2001
2From: Behdad Esfahbod <behdad@behdad.org>
3Date: Mon, 6 Feb 2023 14:51:25 -0700
4Subject: [PATCH] [GPOS] Avoid O(n^2) behavior in mark-attachment
5
6Upstream-Status: Backport from [https://github.com/harfbuzz/harfbuzz/commit/8708b9e081192786c027bb7f5f23d76dbe5c19e8]
7Comment1: The Original Patch [https://github.com/harfbuzz/harfbuzz/commit/85be877925ddbf34f74a1229f3ca1716bb6170dc] causes regression and was reverted. This Patch completes the fix.
8Comment2: The Patch contained files MarkBasePosFormat1.hh and MarkLigPosFormat1.hh which were moved from hb-ot-layout-gpos-table.hh as per https://github.com/harfbuzz/harfbuzz/commit/197d9a5c994eb41c8c89b7b958b26b1eacfeeb00
9CVE: CVE-2023-25193
10Signed-off-by: Siddharth Doshi <sdoshi@mvista.com>
11Signed-off-by: Dhairya Nagodra <dnagodra@cisco.com>
12
13---
14 src/hb-ot-layout-gpos-table.hh | 103 +++++++++++++++++++++++----------
15 src/hb-ot-layout-gsubgpos.hh | 5 +-
16 2 files changed, 78 insertions(+), 30 deletions(-)
17
18diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
19index 024312d..db5f9ae 100644
20--- a/src/hb-ot-layout-gpos-table.hh
21+++ b/src/hb-ot-layout-gpos-table.hh
22@@ -1458,6 +1458,25 @@ struct MarkBasePosFormat1
23
24 const Coverage &get_coverage () const { return this+markCoverage; }
25
26+ static inline bool accept (hb_buffer_t *buffer, unsigned idx)
27+ {
28+ /* We only want to attach to the first of a MultipleSubst sequence.
29+ * https://github.com/harfbuzz/harfbuzz/issues/740
30+ * Reject others...
31+ * ...but stop if we find a mark in the MultipleSubst sequence:
32+ * https://github.com/harfbuzz/harfbuzz/issues/1020 */
33+ return !_hb_glyph_info_multiplied (&buffer->info[idx]) ||
34+ 0 == _hb_glyph_info_get_lig_comp (&buffer->info[idx]) ||
35+ (idx == 0 ||
36+ _hb_glyph_info_is_mark (&buffer->info[idx - 1]) ||
37+ !_hb_glyph_info_multiplied (&buffer->info[idx - 1]) ||
38+ _hb_glyph_info_get_lig_id (&buffer->info[idx]) !=
39+ _hb_glyph_info_get_lig_id (&buffer->info[idx - 1]) ||
40+ _hb_glyph_info_get_lig_comp (&buffer->info[idx]) !=
41+ _hb_glyph_info_get_lig_comp (&buffer->info[idx - 1]) + 1
42+ );
43+ }
44+
45 bool apply (hb_ot_apply_context_t *c) const
46 {
47 TRACE_APPLY (this);
48@@ -1465,37 +1484,46 @@ struct MarkBasePosFormat1
49 unsigned int mark_index = (this+markCoverage).get_coverage (buffer->cur().codepoint);
50 if (likely (mark_index == NOT_COVERED)) return_trace (false);
51
52- /* Now we search backwards for a non-mark glyph */
53+ /* Now we search backwards for a non-mark glyph.
54+ * We don't use skippy_iter.prev() to avoid O(n^2) behavior. */
55+
56 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
57- skippy_iter.reset (buffer->idx, 1);
58 skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
59- do {
60- if (!skippy_iter.prev ()) return_trace (false);
61- /* We only want to attach to the first of a MultipleSubst sequence.
62- * https://github.com/harfbuzz/harfbuzz/issues/740
63- * Reject others...
64- * ...but stop if we find a mark in the MultipleSubst sequence:
65- * https://github.com/harfbuzz/harfbuzz/issues/1020 */
66- if (!_hb_glyph_info_multiplied (&buffer->info[skippy_iter.idx]) ||
67- 0 == _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) ||
68- (skippy_iter.idx == 0 ||
69- _hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx - 1]) ||
70- _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]) !=
71- _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx - 1]) ||
72- _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) !=
73- _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx - 1]) + 1
74- ))
75- break;
76- skippy_iter.reject ();
77- } while (true);
78+ unsigned j;
79+ for (j = buffer->idx; j > c->last_base_until; j--)
80+ {
81+ auto match = skippy_iter.match (buffer->info[j - 1]);
82+ if (match == skippy_iter.MATCH)
83+ {
84+ if (!accept (buffer, j - 1))
85+ match = skippy_iter.SKIP;
86+ }
87+ if (match == skippy_iter.MATCH)
88+ {
89+ c->last_base = (signed) j - 1;
90+ break;
91+ }
92+ }
93+ c->last_base_until = buffer->idx;
94+ if (c->last_base == -1)
95+ {
96+ buffer->unsafe_to_concat_from_outbuffer (0, buffer->idx + 1);
97+ return_trace (false);
98+ }
99+
100+ unsigned idx = (unsigned) c->last_base;
101
102 /* Checking that matched glyph is actually a base glyph by GDEF is too strong; disabled */
103- //if (!_hb_glyph_info_is_base_glyph (&buffer->info[skippy_iter.idx])) { return_trace (false); }
104+ //if (!_hb_glyph_info_is_base_glyph (&buffer->info[idx])) { return_trace (false); }
105
106- unsigned int base_index = (this+baseCoverage).get_coverage (buffer->info[skippy_iter.idx].codepoint);
107- if (base_index == NOT_COVERED) return_trace (false);
108+ unsigned int base_index = (this+baseCoverage).get_coverage (buffer->info[idx].codepoint);
109+ if (base_index == NOT_COVERED)
110+ {
111+ buffer->unsafe_to_concat_from_outbuffer (idx, buffer->idx + 1);
112+ return_trace (false);
113+ }
114
115- return_trace ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx));
116+ return_trace ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, idx));
117 }
118
119 bool subset (hb_subset_context_t *c) const
120@@ -1587,15 +1615,32 @@ struct MarkLigPosFormat1
121 if (likely (mark_index == NOT_COVERED)) return_trace (false);
122
123 /* Now we search backwards for a non-mark glyph */
124+
125 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
126- skippy_iter.reset (buffer->idx, 1);
127 skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
128- if (!skippy_iter.prev ()) return_trace (false);
129+
130+ unsigned j;
131+ for (j = buffer->idx; j > c->last_base_until; j--)
132+ {
133+ auto match = skippy_iter.match (buffer->info[j - 1]);
134+ if (match == skippy_iter.MATCH)
135+ {
136+ c->last_base = (signed) j - 1;
137+ break;
138+ }
139+ }
140+ c->last_base_until = buffer->idx;
141+ if (c->last_base == -1)
142+ {
143+ buffer->unsafe_to_concat_from_outbuffer (0, buffer->idx + 1);
144+ return_trace (false);
145+ }
146+
147+ j = (unsigned) c->last_base;
148
149 /* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */
150- //if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { return_trace (false); }
151+ //if (!_hb_glyph_info_is_ligature (&buffer->info[idx])) { return_trace (false); }
152
153- unsigned int j = skippy_iter.idx;
154 unsigned int lig_index = (this+ligatureCoverage).get_coverage (buffer->info[j].codepoint);
155 if (lig_index == NOT_COVERED) return_trace (false);
156
157diff --git a/src/hb-ot-layout-gsubgpos.hh b/src/hb-ot-layout-gsubgpos.hh
158index 5a7e564..437123c 100644
159--- a/src/hb-ot-layout-gsubgpos.hh
160+++ b/src/hb-ot-layout-gsubgpos.hh
161@@ -503,6 +503,9 @@ struct hb_ot_apply_context_t :
162 uint32_t random_state;
163
164
165+ signed last_base = -1; // GPOS uses
166+ unsigned last_base_until = 0; // GPOS uses
167+
168 hb_ot_apply_context_t (unsigned int table_index_,
169 hb_font_t *font_,
170 hb_buffer_t *buffer_) :
171@@ -536,7 +539,7 @@ struct hb_ot_apply_context_t :
172 iter_context.init (this, true);
173 }
174
175- void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; init_iters (); }
176+ void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; last_base = -1; last_base_until = 0; init_iters (); }
177 void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; init_iters (); }
178 void set_auto_zwnj (bool auto_zwnj_) { auto_zwnj = auto_zwnj_; init_iters (); }
179 void set_random (bool random_) { random = random_; }