From ace98cc65f527dbdfaa3784957535f551c7a600a Mon Sep 17 00:00:00 2001 From: Garret Rieger Date: Mon, 8 Nov 2021 15:47:56 -0800 Subject: [PATCH] [subset] Only sanitize recursion depth in COLR. --- src/hb-ot-color-colr-table.hh | 49 +++++++++++++++++- src/hb-sanitize.hh | 26 +++++++--- ...-minimized-hb-draw-fuzzer-4856957815619584 | Bin 0 -> 486280 bytes 3 files changed, 65 insertions(+), 10 deletions(-) create mode 100644 test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-4856957815619584 diff --git a/src/hb-ot-color-colr-table.hh b/src/hb-ot-color-colr-table.hh index 03476faba..f70084b2f 100644 --- a/src/hb-ot-color-colr-table.hh +++ b/src/hb-ot-color-colr-table.hh @@ -985,7 +985,7 @@ struct ClipList for (const hb_codepoint_t _ : gids.iter ()) { if (_ == start_gid) continue; - + offset = gid_offset_map.get (_); if (_ == prev_gid + 1 && offset == prev_offset) { @@ -1027,7 +1027,7 @@ struct ClipList const hb_set_t& glyphset = *c->plan->_glyphset; const hb_map_t &glyph_map = *c->plan->glyph_map; - + hb_map_t new_gid_offset_map; hb_set_t new_gids; for (const ClipRecord& record : clips.iter ()) @@ -1062,6 +1062,51 @@ struct ClipList struct Paint { + + template + bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const + { + TRACE_SANITIZE (this); + if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); + if (unlikely (!c->check_start_recursion ())) return_trace (c->no_dispatch_return_value ()); + + switch (u.format) { + case 1: return_trace (c->end_recursion (c->dispatch (u.paintformat1, std::forward (ds)...))); + case 2: return_trace (c->end_recursion (c->dispatch (u.paintformat2, std::forward (ds)...))); + case 3: return_trace (c->end_recursion (c->dispatch (u.paintformat3, std::forward (ds)...))); + case 4: return_trace (c->end_recursion (c->dispatch (u.paintformat4, std::forward (ds)...))); + case 5: return_trace (c->end_recursion (c->dispatch (u.paintformat5, std::forward (ds)...))); + case 6: return_trace (c->end_recursion (c->dispatch (u.paintformat6, std::forward (ds)...))); + case 7: return_trace (c->end_recursion (c->dispatch (u.paintformat7, std::forward (ds)...))); + case 8: return_trace (c->end_recursion (c->dispatch (u.paintformat8, std::forward (ds)...))); + case 9: return_trace (c->end_recursion (c->dispatch (u.paintformat9, std::forward (ds)...))); + case 10: return_trace (c->end_recursion (c->dispatch (u.paintformat10, std::forward (ds)...))); + case 11: return_trace (c->end_recursion (c->dispatch (u.paintformat11, std::forward (ds)...))); + case 12: return_trace (c->end_recursion (c->dispatch (u.paintformat12, std::forward (ds)...))); + case 13: return_trace (c->end_recursion (c->dispatch (u.paintformat13, std::forward (ds)...))); + case 14: return_trace (c->end_recursion (c->dispatch (u.paintformat14, std::forward (ds)...))); + case 15: return_trace (c->end_recursion (c->dispatch (u.paintformat15, std::forward (ds)...))); + case 16: return_trace (c->end_recursion (c->dispatch (u.paintformat16, std::forward (ds)...))); + case 17: return_trace (c->end_recursion (c->dispatch (u.paintformat17, std::forward (ds)...))); + case 18: return_trace (c->end_recursion (c->dispatch (u.paintformat18, std::forward (ds)...))); + case 19: return_trace (c->end_recursion (c->dispatch (u.paintformat19, std::forward (ds)...))); + case 20: return_trace (c->end_recursion (c->dispatch (u.paintformat20, std::forward (ds)...))); + case 21: return_trace (c->end_recursion (c->dispatch (u.paintformat21, std::forward (ds)...))); + case 22: return_trace (c->end_recursion (c->dispatch (u.paintformat22, std::forward (ds)...))); + case 23: return_trace (c->end_recursion (c->dispatch (u.paintformat23, std::forward (ds)...))); + case 24: return_trace (c->end_recursion (c->dispatch (u.paintformat24, std::forward (ds)...))); + case 25: return_trace (c->end_recursion (c->dispatch (u.paintformat25, std::forward (ds)...))); + case 26: return_trace (c->end_recursion (c->dispatch (u.paintformat26, std::forward (ds)...))); + case 27: return_trace (c->end_recursion (c->dispatch (u.paintformat27, std::forward (ds)...))); + case 28: return_trace (c->end_recursion (c->dispatch (u.paintformat28, std::forward (ds)...))); + case 29: return_trace (c->end_recursion (c->dispatch (u.paintformat29, std::forward (ds)...))); + case 30: return_trace (c->end_recursion (c->dispatch (u.paintformat30, std::forward (ds)...))); + case 31: return_trace (c->end_recursion (c->dispatch (u.paintformat31, std::forward (ds)...))); + case 32: return_trace (c->end_recursion (c->dispatch (u.paintformat32, std::forward (ds)...))); + default:return_trace (c->end_recursion (c->default_return_value ())); + } + } + template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { diff --git a/src/hb-sanitize.hh b/src/hb-sanitize.hh index d0f2fa585..faeb2aa49 100644 --- a/src/hb-sanitize.hh +++ b/src/hb-sanitize.hh @@ -117,17 +117,16 @@ #define HB_SANITIZE_MAX_SUBTABLES 0x4000 #endif #ifndef HB_SANITIZE_MAX_DEPTH -#define HB_SANITIZE_MAX_DEPTH 5000 +#define HB_SANITIZE_MAX_DEPTH 2500 #endif - struct hb_sanitize_context_t : hb_dispatch_context_t { hb_sanitize_context_t () : - max_depth (0), start (nullptr), end (nullptr), max_ops (0), max_subtables (0), + recursion_depth (0), writable (false), edit_count (0), blob (nullptr), num_glyphs (65536), @@ -148,7 +147,6 @@ struct hb_sanitize_context_t : } private: - int max_depth; template auto _dispatch (const T &obj, hb_priority<1>, Ts&&... ds) HB_AUTO_RETURN ( obj.sanitize (this, std::forward (ds)...) ) @@ -158,9 +156,8 @@ struct hb_sanitize_context_t : public: template auto dispatch (const T &obj, Ts&&... ds) HB_AUTO_RETURN - ( --max_depth > 0 - ? _dispatch (obj, hb_prioritize, std::forward (ds)...) && max_depth++ - : false ) + ( _dispatch (obj, hb_prioritize, std::forward (ds)...) ) + void init (hb_blob_t *b) { @@ -204,7 +201,6 @@ struct hb_sanitize_context_t : void start_processing () { reset_object (); - this->max_depth = HB_SANITIZE_MAX_DEPTH; if (unlikely (hb_unsigned_mul_overflows (this->end - this->start, HB_SANITIZE_MAX_OPS_FACTOR))) this->max_ops = HB_SANITIZE_MAX_OPS_MAX; else @@ -213,6 +209,7 @@ struct hb_sanitize_context_t : (unsigned) HB_SANITIZE_MAX_OPS_MAX); this->edit_count = 0; this->debug_depth = 0; + this->recursion_depth = 0; DEBUG_MSG_LEVEL (SANITIZE, start, 0, +1, "start [%p..%p] (%lu bytes)", @@ -286,6 +283,18 @@ struct hb_sanitize_context_t : return this->check_range (base, a, b, hb_static_size (T)); } + bool check_start_recursion () + { + if (unlikely (recursion_depth >= HB_SANITIZE_MAX_DEPTH)) return false; + return ++recursion_depth; + } + + bool end_recursion (bool result) + { + recursion_depth--; + return result; + } + template bool check_struct (const Type *obj) const { return likely (this->check_range (obj, obj->min_size)); } @@ -397,6 +406,7 @@ struct hb_sanitize_context_t : const char *start, *end; mutable int max_ops, max_subtables; private: + int recursion_depth; bool writable; unsigned int edit_count; hb_blob_t *blob; diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-4856957815619584 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-4856957815619584 new file mode 100644 index 0000000000000000000000000000000000000000..9adb77914e3dea09df1f166ac863bc32f3a165ce GIT binary patch literal 486280 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 literal 0 HcmV?d00001