diff options
3 files changed, 323 insertions, 1 deletions
diff --git a/meta/recipes-graphics/harfbuzz/harfbuzz/CVE-2023-25193-pre1.patch b/meta/recipes-graphics/harfbuzz/harfbuzz/CVE-2023-25193-pre1.patch new file mode 100644 index 0000000000..6721b1bd70 --- /dev/null +++ b/meta/recipes-graphics/harfbuzz/harfbuzz/CVE-2023-25193-pre1.patch | |||
| @@ -0,0 +1,135 @@ | |||
| 1 | From b29fbd16fa82b82bdf0dcb2f13a63f7dc23cf324 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Behdad Esfahbod <behdad@behdad.org> | ||
| 3 | Date: Mon, 6 Feb 2023 13:08:52 -0700 | ||
| 4 | Subject: [PATCH] [gsubgpos] Refactor skippy_iter.match() | ||
| 5 | |||
| 6 | Upstream-Status: Backport from [https://github.com/harfbuzz/harfbuzz/commit/b29fbd16fa82b82bdf0dcb2f13a63f7dc23cf324] | ||
| 7 | Comment1: To backport the fix for CVE-2023-25193, add defination for MATCH, NOT_MATCH and SKIP. | ||
| 8 | Signed-off-by: Siddharth <sdoshi@mvista.com> | ||
| 9 | --- | ||
| 10 | src/hb-ot-layout-gsubgpos.hh | 94 +++++++++++++++++++++--------------- | ||
| 11 | 1 file changed, 54 insertions(+), 40 deletions(-) | ||
| 12 | |||
| 13 | diff --git a/src/hb-ot-layout-gsubgpos.hh b/src/hb-ot-layout-gsubgpos.hh | ||
| 14 | index d9a068c..d17a4da 100644 | ||
| 15 | --- a/src/hb-ot-layout-gsubgpos.hh | ||
| 16 | +++ b/src/hb-ot-layout-gsubgpos.hh | ||
| 17 | @@ -522,33 +522,52 @@ struct hb_ot_apply_context_t : | ||
| 18 | may_skip (const hb_glyph_info_t &info) const | ||
| 19 | { return matcher.may_skip (c, info); } | ||
| 20 | |||
| 21 | + enum match_t { | ||
| 22 | + MATCH, | ||
| 23 | + NOT_MATCH, | ||
| 24 | + SKIP | ||
| 25 | + }; | ||
| 26 | + | ||
| 27 | + match_t match (hb_glyph_info_t &info) | ||
| 28 | + { | ||
| 29 | + matcher_t::may_skip_t skip = matcher.may_skip (c, info); | ||
| 30 | + if (unlikely (skip == matcher_t::SKIP_YES)) | ||
| 31 | + return SKIP; | ||
| 32 | + | ||
| 33 | + matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data); | ||
| 34 | + if (match == matcher_t::MATCH_YES || | ||
| 35 | + (match == matcher_t::MATCH_MAYBE && | ||
| 36 | + skip == matcher_t::SKIP_NO)) | ||
| 37 | + return MATCH; | ||
| 38 | + | ||
| 39 | + if (skip == matcher_t::SKIP_NO) | ||
| 40 | + return NOT_MATCH; | ||
| 41 | + | ||
| 42 | + return SKIP; | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | bool next (unsigned *unsafe_to = nullptr) | ||
| 46 | { | ||
| 47 | assert (num_items > 0); | ||
| 48 | while (idx + num_items < end) | ||
| 49 | { | ||
| 50 | idx++; | ||
| 51 | - const hb_glyph_info_t &info = c->buffer->info[idx]; | ||
| 52 | - | ||
| 53 | - matcher_t::may_skip_t skip = matcher.may_skip (c, info); | ||
| 54 | - if (unlikely (skip == matcher_t::SKIP_YES)) | ||
| 55 | - continue; | ||
| 56 | - | ||
| 57 | - matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data); | ||
| 58 | - if (match == matcher_t::MATCH_YES || | ||
| 59 | - (match == matcher_t::MATCH_MAYBE && | ||
| 60 | - skip == matcher_t::SKIP_NO)) | ||
| 61 | - { | ||
| 62 | - num_items--; | ||
| 63 | - if (match_glyph_data) match_glyph_data++; | ||
| 64 | - return true; | ||
| 65 | - } | ||
| 66 | - | ||
| 67 | - if (skip == matcher_t::SKIP_NO) | ||
| 68 | + switch (match (c->buffer->info[idx])) | ||
| 69 | { | ||
| 70 | - if (unsafe_to) | ||
| 71 | - *unsafe_to = idx + 1; | ||
| 72 | - return false; | ||
| 73 | + case MATCH: | ||
| 74 | + { | ||
| 75 | + num_items--; | ||
| 76 | + if (match_glyph_data) match_glyph_data++; | ||
| 77 | + return true; | ||
| 78 | + } | ||
| 79 | + case NOT_MATCH: | ||
| 80 | + { | ||
| 81 | + if (unsafe_to) | ||
| 82 | + *unsafe_to = idx + 1; | ||
| 83 | + return false; | ||
| 84 | + } | ||
| 85 | + case SKIP: | ||
| 86 | + continue; | ||
| 87 | } | ||
| 88 | } | ||
| 89 | if (unsafe_to) | ||
| 90 | @@ -561,27 +580,22 @@ struct hb_ot_apply_context_t : | ||
| 91 | while (idx > num_items - 1) | ||
| 92 | { | ||
| 93 | idx--; | ||
| 94 | - const hb_glyph_info_t &info = c->buffer->out_info[idx]; | ||
| 95 | - | ||
| 96 | - matcher_t::may_skip_t skip = matcher.may_skip (c, info); | ||
| 97 | - if (unlikely (skip == matcher_t::SKIP_YES)) | ||
| 98 | - continue; | ||
| 99 | - | ||
| 100 | - matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data); | ||
| 101 | - if (match == matcher_t::MATCH_YES || | ||
| 102 | - (match == matcher_t::MATCH_MAYBE && | ||
| 103 | - skip == matcher_t::SKIP_NO)) | ||
| 104 | - { | ||
| 105 | - num_items--; | ||
| 106 | - if (match_glyph_data) match_glyph_data++; | ||
| 107 | - return true; | ||
| 108 | - } | ||
| 109 | - | ||
| 110 | - if (skip == matcher_t::SKIP_NO) | ||
| 111 | + switch (match (c->buffer->out_info[idx])) | ||
| 112 | { | ||
| 113 | - if (unsafe_from) | ||
| 114 | - *unsafe_from = hb_max (1u, idx) - 1u; | ||
| 115 | - return false; | ||
| 116 | + case MATCH: | ||
| 117 | + { | ||
| 118 | + num_items--; | ||
| 119 | + if (match_glyph_data) match_glyph_data++; | ||
| 120 | + return true; | ||
| 121 | + } | ||
| 122 | + case NOT_MATCH: | ||
| 123 | + { | ||
| 124 | + if (unsafe_from) | ||
| 125 | + *unsafe_from = hb_max (1u, idx) - 1u; | ||
| 126 | + return false; | ||
| 127 | + } | ||
| 128 | + case SKIP: | ||
| 129 | + continue; | ||
| 130 | } | ||
| 131 | } | ||
| 132 | if (unsafe_from) | ||
| 133 | -- | ||
| 134 | 2.25.1 | ||
| 135 | |||
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..a1ec1422cc --- /dev/null +++ b/meta/recipes-graphics/harfbuzz/harfbuzz/CVE-2023-25193.patch | |||
| @@ -0,0 +1,185 @@ | |||
| 1 | From 8708b9e081192786c027bb7f5f23d76dbe5c19e8 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Behdad Esfahbod <behdad@behdad.org> | ||
| 3 | Date: Mon, 6 Feb 2023 14:51:25 -0700 | ||
| 4 | Subject: [PATCH] [GPOS] Avoid O(n^2) behavior in mark-attachment | ||
| 5 | |||
| 6 | Upstream-Status: Backport from [https://github.com/harfbuzz/harfbuzz/commit/8708b9e081192786c027bb7f5f23d76dbe5c19e8] | ||
| 7 | Comment1: The Original Patch [https://github.com/harfbuzz/harfbuzz/commit/85be877925ddbf34f74a1229f3ca1716bb6170dc] causes regression and was reverted. This Patch completes the fix. | ||
| 8 | Comment2: 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 | ||
| 9 | CVE: CVE-2023-25193 | ||
| 10 | Signed-off-by: Siddharth Doshi <sdoshi@mvista.com> | ||
| 11 | --- | ||
| 12 | src/hb-ot-layout-gpos-table.hh | 98 ++++++++++++++++++++++------------ | ||
| 13 | src/hb-ot-layout-gsubgpos.hh | 5 +- | ||
| 14 | 2 files changed, 68 insertions(+), 35 deletions(-) | ||
| 15 | |||
| 16 | diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh | ||
| 17 | index 2f9186a..46b09d0 100644 | ||
| 18 | --- a/src/hb-ot-layout-gpos-table.hh | ||
| 19 | +++ b/src/hb-ot-layout-gpos-table.hh | ||
| 20 | @@ -2150,6 +2150,25 @@ struct MarkBasePosFormat1 | ||
| 21 | |||
| 22 | const Coverage &get_coverage () const { return this+markCoverage; } | ||
| 23 | |||
| 24 | + static inline bool accept (hb_buffer_t *buffer, unsigned idx) | ||
| 25 | + { | ||
| 26 | + /* We only want to attach to the first of a MultipleSubst sequence. | ||
| 27 | + * https://github.com/harfbuzz/harfbuzz/issues/740 | ||
| 28 | + * Reject others... | ||
| 29 | + * ...but stop if we find a mark in the MultipleSubst sequence: | ||
| 30 | + * https://github.com/harfbuzz/harfbuzz/issues/1020 */ | ||
| 31 | + return !_hb_glyph_info_multiplied (&buffer->info[idx]) || | ||
| 32 | + 0 == _hb_glyph_info_get_lig_comp (&buffer->info[idx]) || | ||
| 33 | + (idx == 0 || | ||
| 34 | + _hb_glyph_info_is_mark (&buffer->info[idx - 1]) || | ||
| 35 | + !_hb_glyph_info_multiplied (&buffer->info[idx - 1]) || | ||
| 36 | + _hb_glyph_info_get_lig_id (&buffer->info[idx]) != | ||
| 37 | + _hb_glyph_info_get_lig_id (&buffer->info[idx - 1]) || | ||
| 38 | + _hb_glyph_info_get_lig_comp (&buffer->info[idx]) != | ||
| 39 | + _hb_glyph_info_get_lig_comp (&buffer->info[idx - 1]) + 1 | ||
| 40 | + ); | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | bool apply (hb_ot_apply_context_t *c) const | ||
| 44 | { | ||
| 45 | TRACE_APPLY (this); | ||
| 46 | @@ -2157,47 +2176,46 @@ struct MarkBasePosFormat1 | ||
| 47 | unsigned int mark_index = (this+markCoverage).get_coverage (buffer->cur().codepoint); | ||
| 48 | if (likely (mark_index == NOT_COVERED)) return_trace (false); | ||
| 49 | |||
| 50 | - /* Now we search backwards for a non-mark glyph */ | ||
| 51 | + /* Now we search backwards for a non-mark glyph. | ||
| 52 | + * We don't use skippy_iter.prev() to avoid O(n^2) behavior. */ | ||
| 53 | + | ||
| 54 | hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; | ||
| 55 | - skippy_iter.reset (buffer->idx, 1); | ||
| 56 | skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks); | ||
| 57 | - do { | ||
| 58 | - unsigned unsafe_from; | ||
| 59 | - if (!skippy_iter.prev (&unsafe_from)) | ||
| 60 | + unsigned j; | ||
| 61 | + for (j = buffer->idx; j > c->last_base_until; j--) | ||
| 62 | + { | ||
| 63 | + auto match = skippy_iter.match (buffer->info[j - 1]); | ||
| 64 | + if (match == skippy_iter.MATCH) | ||
| 65 | { | ||
| 66 | - buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1); | ||
| 67 | - return_trace (false); | ||
| 68 | + if (!accept (buffer, j - 1)) | ||
| 69 | + match = skippy_iter.SKIP; | ||
| 70 | } | ||
| 71 | + if (match == skippy_iter.MATCH) | ||
| 72 | + { | ||
| 73 | + c->last_base = (signed) j - 1; | ||
| 74 | + break; | ||
| 75 | + } | ||
| 76 | + } | ||
| 77 | + c->last_base_until = buffer->idx; | ||
| 78 | + if (c->last_base == -1) | ||
| 79 | + { | ||
| 80 | + buffer->unsafe_to_concat_from_outbuffer (0, buffer->idx + 1); | ||
| 81 | + return_trace (false); | ||
| 82 | + } | ||
| 83 | |||
| 84 | - /* We only want to attach to the first of a MultipleSubst sequence. | ||
| 85 | - * https://github.com/harfbuzz/harfbuzz/issues/740 | ||
| 86 | - * Reject others... | ||
| 87 | - * ...but stop if we find a mark in the MultipleSubst sequence: | ||
| 88 | - * https://github.com/harfbuzz/harfbuzz/issues/1020 */ | ||
| 89 | - if (!_hb_glyph_info_multiplied (&buffer->info[skippy_iter.idx]) || | ||
| 90 | - 0 == _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) || | ||
| 91 | - (skippy_iter.idx == 0 || | ||
| 92 | - _hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx - 1]) || | ||
| 93 | - _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]) != | ||
| 94 | - _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx - 1]) || | ||
| 95 | - _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) != | ||
| 96 | - _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx - 1]) + 1 | ||
| 97 | - )) | ||
| 98 | - break; | ||
| 99 | - skippy_iter.reject (); | ||
| 100 | - } while (true); | ||
| 101 | + unsigned idx = (unsigned) c->last_base; | ||
| 102 | |||
| 103 | /* Checking that matched glyph is actually a base glyph by GDEF is too strong; disabled */ | ||
| 104 | - //if (!_hb_glyph_info_is_base_glyph (&buffer->info[skippy_iter.idx])) { return_trace (false); } | ||
| 105 | + //if (!_hb_glyph_info_is_base_glyph (&buffer->info[idx])) { return_trace (false); } | ||
| 106 | |||
| 107 | - unsigned int base_index = (this+baseCoverage).get_coverage (buffer->info[skippy_iter.idx].codepoint); | ||
| 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 (skippy_iter.idx, buffer->idx + 1); | ||
| 112 | + buffer->unsafe_to_concat_from_outbuffer (idx, buffer->idx + 1); | ||
| 113 | return_trace (false); | ||
| 114 | } | ||
| 115 | |||
| 116 | - return_trace ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx)); | ||
| 117 | + return_trace ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, idx)); | ||
| 118 | } | ||
| 119 | |||
| 120 | bool subset (hb_subset_context_t *c) const | ||
| 121 | @@ -2423,20 +2441,32 @@ struct MarkLigPosFormat1 | ||
| 122 | if (likely (mark_index == NOT_COVERED)) return_trace (false); | ||
| 123 | |||
| 124 | /* Now we search backwards for a non-mark glyph */ | ||
| 125 | + | ||
| 126 | hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; | ||
| 127 | - skippy_iter.reset (buffer->idx, 1); | ||
| 128 | skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks); | ||
| 129 | - unsigned unsafe_from; | ||
| 130 | - if (!skippy_iter.prev (&unsafe_from)) | ||
| 131 | + | ||
| 132 | + unsigned j; | ||
| 133 | + for (j = buffer->idx; j > c->last_base_until; j--) | ||
| 134 | { | ||
| 135 | - buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1); | ||
| 136 | + auto match = skippy_iter.match (buffer->info[j - 1]); | ||
| 137 | + if (match == skippy_iter.MATCH) | ||
| 138 | + { | ||
| 139 | + c->last_base = (signed) j - 1; | ||
| 140 | + break; | ||
| 141 | + } | ||
| 142 | + } | ||
| 143 | + c->last_base_until = buffer->idx; | ||
| 144 | + if (c->last_base == -1) | ||
| 145 | + { | ||
| 146 | + buffer->unsafe_to_concat_from_outbuffer (0, buffer->idx + 1); | ||
| 147 | return_trace (false); | ||
| 148 | } | ||
| 149 | |||
| 150 | + j = (unsigned) c->last_base; | ||
| 151 | + | ||
| 152 | /* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */ | ||
| 153 | - //if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { return_trace (false); } | ||
| 154 | + //if (!_hb_glyph_info_is_ligature (&buffer->info[j])) { return_trace (false); } | ||
| 155 | |||
| 156 | - unsigned int j = skippy_iter.idx; | ||
| 157 | unsigned int lig_index = (this+ligatureCoverage).get_coverage (buffer->info[j].codepoint); | ||
| 158 | if (lig_index == NOT_COVERED) | ||
| 159 | { | ||
| 160 | diff --git a/src/hb-ot-layout-gsubgpos.hh b/src/hb-ot-layout-gsubgpos.hh | ||
| 161 | index 65de131..d9a068c 100644 | ||
| 162 | --- a/src/hb-ot-layout-gsubgpos.hh | ||
| 163 | +++ b/src/hb-ot-layout-gsubgpos.hh | ||
| 164 | @@ -641,6 +641,9 @@ struct hb_ot_apply_context_t : | ||
| 165 | uint32_t random_state; | ||
| 166 | |||
| 167 | |||
| 168 | + signed last_base = -1; // GPOS uses | ||
| 169 | + unsigned last_base_until = 0; // GPOS uses | ||
| 170 | + | ||
| 171 | hb_ot_apply_context_t (unsigned int table_index_, | ||
| 172 | hb_font_t *font_, | ||
| 173 | hb_buffer_t *buffer_) : | ||
| 174 | @@ -673,7 +676,7 @@ struct hb_ot_apply_context_t : | ||
| 175 | iter_context.init (this, true); | ||
| 176 | } | ||
| 177 | |||
| 178 | - void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; init_iters (); } | ||
| 179 | + void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; last_base = -1; last_base_until = 0; init_iters (); } | ||
| 180 | void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; init_iters (); } | ||
| 181 | void set_auto_zwnj (bool auto_zwnj_) { auto_zwnj = auto_zwnj_; init_iters (); } | ||
| 182 | void set_random (bool random_) { random = random_; } | ||
| 183 | -- | ||
| 184 | 2.25.1 | ||
| 185 | |||
diff --git a/meta/recipes-graphics/harfbuzz/harfbuzz_4.0.1.bb b/meta/recipes-graphics/harfbuzz/harfbuzz_4.0.1.bb index bdbb322e42..f7dc61ebd5 100644 --- a/meta/recipes-graphics/harfbuzz/harfbuzz_4.0.1.bb +++ b/meta/recipes-graphics/harfbuzz/harfbuzz_4.0.1.bb | |||
| @@ -13,7 +13,9 @@ UPSTREAM_CHECK_REGEX = "harfbuzz-(?P<pver>\d+(\.\d+)+).tar" | |||
| 13 | 13 | ||
| 14 | SRC_URI = "https://github.com/${BPN}/${BPN}/releases/download/${PV}/${BPN}-${PV}.tar.xz \ | 14 | SRC_URI = "https://github.com/${BPN}/${BPN}/releases/download/${PV}/${BPN}-${PV}.tar.xz \ |
| 15 | file://CVE-2022-33068.patch \ | 15 | file://CVE-2022-33068.patch \ |
| 16 | file://0001-Fix-conditional.patch" | 16 | file://0001-Fix-conditional.patch \ |
| 17 | file://CVE-2023-25193-pre1.patch \ | ||
| 18 | file://CVE-2023-25193.patch" | ||
| 17 | SRC_URI[sha256sum] = "98f68777272db6cd7a3d5152bac75083cd52a26176d87bc04c8b3929d33bce49" | 19 | SRC_URI[sha256sum] = "98f68777272db6cd7a3d5152bac75083cd52a26176d87bc04c8b3929d33bce49" |
| 18 | 20 | ||
| 19 | inherit meson pkgconfig lib_package gtk-doc gobject-introspection | 21 | inherit meson pkgconfig lib_package gtk-doc gobject-introspection |
