1*2d1272b8SAndroid Build Coastguard Worker /* 2*2d1272b8SAndroid Build Coastguard Worker * Copyright © 2007,2008,2009,2010 Red Hat, Inc. 3*2d1272b8SAndroid Build Coastguard Worker * Copyright © 2012,2018 Google, Inc. 4*2d1272b8SAndroid Build Coastguard Worker * 5*2d1272b8SAndroid Build Coastguard Worker * This is part of HarfBuzz, a text shaping library. 6*2d1272b8SAndroid Build Coastguard Worker * 7*2d1272b8SAndroid Build Coastguard Worker * Permission is hereby granted, without written agreement and without 8*2d1272b8SAndroid Build Coastguard Worker * license or royalty fees, to use, copy, modify, and distribute this 9*2d1272b8SAndroid Build Coastguard Worker * software and its documentation for any purpose, provided that the 10*2d1272b8SAndroid Build Coastguard Worker * above copyright notice and the following two paragraphs appear in 11*2d1272b8SAndroid Build Coastguard Worker * all copies of this software. 12*2d1272b8SAndroid Build Coastguard Worker * 13*2d1272b8SAndroid Build Coastguard Worker * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 14*2d1272b8SAndroid Build Coastguard Worker * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 15*2d1272b8SAndroid Build Coastguard Worker * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 16*2d1272b8SAndroid Build Coastguard Worker * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 17*2d1272b8SAndroid Build Coastguard Worker * DAMAGE. 18*2d1272b8SAndroid Build Coastguard Worker * 19*2d1272b8SAndroid Build Coastguard Worker * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 20*2d1272b8SAndroid Build Coastguard Worker * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 21*2d1272b8SAndroid Build Coastguard Worker * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 22*2d1272b8SAndroid Build Coastguard Worker * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 23*2d1272b8SAndroid Build Coastguard Worker * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 24*2d1272b8SAndroid Build Coastguard Worker * 25*2d1272b8SAndroid Build Coastguard Worker * Red Hat Author(s): Behdad Esfahbod 26*2d1272b8SAndroid Build Coastguard Worker * Google Author(s): Behdad Esfahbod 27*2d1272b8SAndroid Build Coastguard Worker */ 28*2d1272b8SAndroid Build Coastguard Worker 29*2d1272b8SAndroid Build Coastguard Worker #ifndef HB_SANITIZE_HH 30*2d1272b8SAndroid Build Coastguard Worker #define HB_SANITIZE_HH 31*2d1272b8SAndroid Build Coastguard Worker 32*2d1272b8SAndroid Build Coastguard Worker #include "hb.hh" 33*2d1272b8SAndroid Build Coastguard Worker #include "hb-blob.hh" 34*2d1272b8SAndroid Build Coastguard Worker #include "hb-dispatch.hh" 35*2d1272b8SAndroid Build Coastguard Worker 36*2d1272b8SAndroid Build Coastguard Worker 37*2d1272b8SAndroid Build Coastguard Worker /* 38*2d1272b8SAndroid Build Coastguard Worker * Sanitize 39*2d1272b8SAndroid Build Coastguard Worker * 40*2d1272b8SAndroid Build Coastguard Worker * 41*2d1272b8SAndroid Build Coastguard Worker * === Introduction === 42*2d1272b8SAndroid Build Coastguard Worker * 43*2d1272b8SAndroid Build Coastguard Worker * The sanitize machinery is at the core of our zero-cost font loading. We 44*2d1272b8SAndroid Build Coastguard Worker * mmap() font file into memory and create a blob out of it. Font subtables 45*2d1272b8SAndroid Build Coastguard Worker * are returned as a readonly sub-blob of the main font blob. These table 46*2d1272b8SAndroid Build Coastguard Worker * blobs are then sanitized before use, to ensure invalid memory access does 47*2d1272b8SAndroid Build Coastguard Worker * not happen. The toplevel sanitize API use is like, eg. to load the 'head' 48*2d1272b8SAndroid Build Coastguard Worker * table: 49*2d1272b8SAndroid Build Coastguard Worker * 50*2d1272b8SAndroid Build Coastguard Worker * hb_blob_t *head_blob = hb_sanitize_context_t ().reference_table<OT::head> (face); 51*2d1272b8SAndroid Build Coastguard Worker * 52*2d1272b8SAndroid Build Coastguard Worker * The blob then can be converted to a head table struct with: 53*2d1272b8SAndroid Build Coastguard Worker * 54*2d1272b8SAndroid Build Coastguard Worker * const head *head_table = head_blob->as<head> (); 55*2d1272b8SAndroid Build Coastguard Worker * 56*2d1272b8SAndroid Build Coastguard Worker * What the reference_table does is, to call hb_face_reference_table() to load 57*2d1272b8SAndroid Build Coastguard Worker * the table blob, sanitize it and return either the sanitized blob, or empty 58*2d1272b8SAndroid Build Coastguard Worker * blob if sanitization failed. The blob->as() function returns the null 59*2d1272b8SAndroid Build Coastguard Worker * object of its template type argument if the blob is empty. Otherwise, it 60*2d1272b8SAndroid Build Coastguard Worker * just casts the blob contents to the desired type. 61*2d1272b8SAndroid Build Coastguard Worker * 62*2d1272b8SAndroid Build Coastguard Worker * Sanitizing a blob of data with a type T works as follows (with minor 63*2d1272b8SAndroid Build Coastguard Worker * simplification): 64*2d1272b8SAndroid Build Coastguard Worker * 65*2d1272b8SAndroid Build Coastguard Worker * - Cast blob content to T*, call sanitize() method of it, 66*2d1272b8SAndroid Build Coastguard Worker * - If sanitize succeeded, return blob. 67*2d1272b8SAndroid Build Coastguard Worker * - Otherwise, if blob is not writable, try making it writable, 68*2d1272b8SAndroid Build Coastguard Worker * or copy if cannot be made writable in-place, 69*2d1272b8SAndroid Build Coastguard Worker * - Call sanitize() again. Return blob if sanitize succeeded. 70*2d1272b8SAndroid Build Coastguard Worker * - Return empty blob otherwise. 71*2d1272b8SAndroid Build Coastguard Worker * 72*2d1272b8SAndroid Build Coastguard Worker * 73*2d1272b8SAndroid Build Coastguard Worker * === The sanitize() contract === 74*2d1272b8SAndroid Build Coastguard Worker * 75*2d1272b8SAndroid Build Coastguard Worker * The sanitize() method of each object type shall return true if it's safe to 76*2d1272b8SAndroid Build Coastguard Worker * call other methods of the object, and %false otherwise. 77*2d1272b8SAndroid Build Coastguard Worker * 78*2d1272b8SAndroid Build Coastguard Worker * Note that what sanitize() checks for might align with what the specification 79*2d1272b8SAndroid Build Coastguard Worker * describes as valid table data, but does not have to be. In particular, we 80*2d1272b8SAndroid Build Coastguard Worker * do NOT want to be pedantic and concern ourselves with validity checks that 81*2d1272b8SAndroid Build Coastguard Worker * are irrelevant to our use of the table. On the contrary, we want to be 82*2d1272b8SAndroid Build Coastguard Worker * lenient with error handling and accept invalid data to the extent that it 83*2d1272b8SAndroid Build Coastguard Worker * does not impose extra burden on us. 84*2d1272b8SAndroid Build Coastguard Worker * 85*2d1272b8SAndroid Build Coastguard Worker * Based on the sanitize contract, one can see that what we check for depends 86*2d1272b8SAndroid Build Coastguard Worker * on how we use the data in other table methods. Ie. if other table methods 87*2d1272b8SAndroid Build Coastguard Worker * assume that offsets do NOT point out of the table data block, then that's 88*2d1272b8SAndroid Build Coastguard Worker * something sanitize() must check for (GSUB/GPOS/GDEF/etc work this way). On 89*2d1272b8SAndroid Build Coastguard Worker * the other hand, if other methods do such checks themselves, then sanitize() 90*2d1272b8SAndroid Build Coastguard Worker * does not have to bother with them (glyf/local work this way). The choice 91*2d1272b8SAndroid Build Coastguard Worker * depends on the table structure and sanitize() performance. For example, to 92*2d1272b8SAndroid Build Coastguard Worker * check glyf/loca offsets in sanitize() would cost O(num-glyphs). We try hard 93*2d1272b8SAndroid Build Coastguard Worker * to avoid such costs during font loading. By postponing such checks to the 94*2d1272b8SAndroid Build Coastguard Worker * actual glyph loading, we reduce the sanitize cost to O(1) and total runtime 95*2d1272b8SAndroid Build Coastguard Worker * cost to O(used-glyphs). As such, this is preferred. 96*2d1272b8SAndroid Build Coastguard Worker * 97*2d1272b8SAndroid Build Coastguard Worker * The same argument can be made re GSUB/GPOS/GDEF, but there, the table 98*2d1272b8SAndroid Build Coastguard Worker * structure is so complicated that by checking all offsets at sanitize() time, 99*2d1272b8SAndroid Build Coastguard Worker * we make the code much simpler in other methods, as offsets and referenced 100*2d1272b8SAndroid Build Coastguard Worker * objects do not need to be validated at each use site. 101*2d1272b8SAndroid Build Coastguard Worker */ 102*2d1272b8SAndroid Build Coastguard Worker 103*2d1272b8SAndroid Build Coastguard Worker /* This limits sanitizing time on really broken fonts. */ 104*2d1272b8SAndroid Build Coastguard Worker #ifndef HB_SANITIZE_MAX_EDITS 105*2d1272b8SAndroid Build Coastguard Worker #define HB_SANITIZE_MAX_EDITS 32 106*2d1272b8SAndroid Build Coastguard Worker #endif 107*2d1272b8SAndroid Build Coastguard Worker #ifndef HB_SANITIZE_MAX_OPS_FACTOR 108*2d1272b8SAndroid Build Coastguard Worker #define HB_SANITIZE_MAX_OPS_FACTOR 64 109*2d1272b8SAndroid Build Coastguard Worker #endif 110*2d1272b8SAndroid Build Coastguard Worker #ifndef HB_SANITIZE_MAX_OPS_MIN 111*2d1272b8SAndroid Build Coastguard Worker #define HB_SANITIZE_MAX_OPS_MIN 16384 112*2d1272b8SAndroid Build Coastguard Worker #endif 113*2d1272b8SAndroid Build Coastguard Worker #ifndef HB_SANITIZE_MAX_OPS_MAX 114*2d1272b8SAndroid Build Coastguard Worker #define HB_SANITIZE_MAX_OPS_MAX 0x3FFFFFFF 115*2d1272b8SAndroid Build Coastguard Worker #endif 116*2d1272b8SAndroid Build Coastguard Worker #ifndef HB_SANITIZE_MAX_SUBTABLES 117*2d1272b8SAndroid Build Coastguard Worker #define HB_SANITIZE_MAX_SUBTABLES 0x4000 118*2d1272b8SAndroid Build Coastguard Worker #endif 119*2d1272b8SAndroid Build Coastguard Worker 120*2d1272b8SAndroid Build Coastguard Worker struct hb_sanitize_context_t : 121*2d1272b8SAndroid Build Coastguard Worker hb_dispatch_context_t<hb_sanitize_context_t, bool, HB_DEBUG_SANITIZE> 122*2d1272b8SAndroid Build Coastguard Worker { hb_sanitize_context_thb_sanitize_context_t123*2d1272b8SAndroid Build Coastguard Worker hb_sanitize_context_t () : 124*2d1272b8SAndroid Build Coastguard Worker start (nullptr), end (nullptr), 125*2d1272b8SAndroid Build Coastguard Worker length (0), 126*2d1272b8SAndroid Build Coastguard Worker max_ops (0), max_subtables (0), 127*2d1272b8SAndroid Build Coastguard Worker recursion_depth (0), 128*2d1272b8SAndroid Build Coastguard Worker writable (false), edit_count (0), 129*2d1272b8SAndroid Build Coastguard Worker blob (nullptr), 130*2d1272b8SAndroid Build Coastguard Worker num_glyphs (65536), 131*2d1272b8SAndroid Build Coastguard Worker num_glyphs_set (false), 132*2d1272b8SAndroid Build Coastguard Worker lazy_some_gpos (false) {} 133*2d1272b8SAndroid Build Coastguard Worker get_namehb_sanitize_context_t134*2d1272b8SAndroid Build Coastguard Worker const char *get_name () { return "SANITIZE"; } 135*2d1272b8SAndroid Build Coastguard Worker template <typename T, typename F> may_dispatchhb_sanitize_context_t136*2d1272b8SAndroid Build Coastguard Worker bool may_dispatch (const T *obj HB_UNUSED, const F *format) 137*2d1272b8SAndroid Build Coastguard Worker { 138*2d1272b8SAndroid Build Coastguard Worker return format->sanitize (this) && 139*2d1272b8SAndroid Build Coastguard Worker hb_barrier (); 140*2d1272b8SAndroid Build Coastguard Worker } default_return_valuehb_sanitize_context_t141*2d1272b8SAndroid Build Coastguard Worker static return_t default_return_value () { return true; } no_dispatch_return_valuehb_sanitize_context_t142*2d1272b8SAndroid Build Coastguard Worker static return_t no_dispatch_return_value () { return false; } stop_sublookup_iterationhb_sanitize_context_t143*2d1272b8SAndroid Build Coastguard Worker bool stop_sublookup_iteration (const return_t r) const { return !r; } 144*2d1272b8SAndroid Build Coastguard Worker visit_subtableshb_sanitize_context_t145*2d1272b8SAndroid Build Coastguard Worker bool visit_subtables (unsigned count) 146*2d1272b8SAndroid Build Coastguard Worker { 147*2d1272b8SAndroid Build Coastguard Worker max_subtables += count; 148*2d1272b8SAndroid Build Coastguard Worker return max_subtables < HB_SANITIZE_MAX_SUBTABLES; 149*2d1272b8SAndroid Build Coastguard Worker } 150*2d1272b8SAndroid Build Coastguard Worker 151*2d1272b8SAndroid Build Coastguard Worker private: 152*2d1272b8SAndroid Build Coastguard Worker template <typename T, typename ...Ts> auto 153*2d1272b8SAndroid Build Coastguard Worker _dispatch (const T &obj, hb_priority<1>, Ts&&... ds) HB_AUTO_RETURN 154*2d1272b8SAndroid Build Coastguard Worker ( obj.sanitize (this, std::forward<Ts> (ds)...) ) 155*2d1272b8SAndroid Build Coastguard Worker template <typename T, typename ...Ts> auto 156*2d1272b8SAndroid Build Coastguard Worker _dispatch (const T &obj, hb_priority<0>, Ts&&... ds) HB_AUTO_RETURN 157*2d1272b8SAndroid Build Coastguard Worker ( obj.dispatch (this, std::forward<Ts> (ds)...) ) 158*2d1272b8SAndroid Build Coastguard Worker public: 159*2d1272b8SAndroid Build Coastguard Worker template <typename T, typename ...Ts> auto dispatchhb_sanitize_context_t160*2d1272b8SAndroid Build Coastguard Worker dispatch (const T &obj, Ts&&... ds) HB_AUTO_RETURN 161*2d1272b8SAndroid Build Coastguard Worker ( _dispatch (obj, hb_prioritize, std::forward<Ts> (ds)...) ) 162*2d1272b8SAndroid Build Coastguard Worker 163*2d1272b8SAndroid Build Coastguard Worker hb_sanitize_context_t (hb_blob_t *b) : hb_sanitize_context_t () 164*2d1272b8SAndroid Build Coastguard Worker { 165*2d1272b8SAndroid Build Coastguard Worker init (b); 166*2d1272b8SAndroid Build Coastguard Worker 167*2d1272b8SAndroid Build Coastguard Worker if (blob) 168*2d1272b8SAndroid Build Coastguard Worker start_processing (); 169*2d1272b8SAndroid Build Coastguard Worker } 170*2d1272b8SAndroid Build Coastguard Worker ~hb_sanitize_context_thb_sanitize_context_t171*2d1272b8SAndroid Build Coastguard Worker ~hb_sanitize_context_t () 172*2d1272b8SAndroid Build Coastguard Worker { 173*2d1272b8SAndroid Build Coastguard Worker if (blob) 174*2d1272b8SAndroid Build Coastguard Worker end_processing (); 175*2d1272b8SAndroid Build Coastguard Worker } 176*2d1272b8SAndroid Build Coastguard Worker inithb_sanitize_context_t177*2d1272b8SAndroid Build Coastguard Worker void init (hb_blob_t *b) 178*2d1272b8SAndroid Build Coastguard Worker { 179*2d1272b8SAndroid Build Coastguard Worker this->blob = hb_blob_reference (b); 180*2d1272b8SAndroid Build Coastguard Worker this->writable = false; 181*2d1272b8SAndroid Build Coastguard Worker } 182*2d1272b8SAndroid Build Coastguard Worker set_num_glyphshb_sanitize_context_t183*2d1272b8SAndroid Build Coastguard Worker void set_num_glyphs (unsigned int num_glyphs_) 184*2d1272b8SAndroid Build Coastguard Worker { 185*2d1272b8SAndroid Build Coastguard Worker num_glyphs = num_glyphs_; 186*2d1272b8SAndroid Build Coastguard Worker num_glyphs_set = true; 187*2d1272b8SAndroid Build Coastguard Worker } get_num_glyphshb_sanitize_context_t188*2d1272b8SAndroid Build Coastguard Worker unsigned int get_num_glyphs () { return num_glyphs; } 189*2d1272b8SAndroid Build Coastguard Worker set_max_opshb_sanitize_context_t190*2d1272b8SAndroid Build Coastguard Worker void set_max_ops (int max_ops_) { max_ops = max_ops_; } 191*2d1272b8SAndroid Build Coastguard Worker 192*2d1272b8SAndroid Build Coastguard Worker template <typename T> set_objecthb_sanitize_context_t193*2d1272b8SAndroid Build Coastguard Worker void set_object (const T *obj) 194*2d1272b8SAndroid Build Coastguard Worker { 195*2d1272b8SAndroid Build Coastguard Worker reset_object (); 196*2d1272b8SAndroid Build Coastguard Worker 197*2d1272b8SAndroid Build Coastguard Worker if (!obj) return; 198*2d1272b8SAndroid Build Coastguard Worker 199*2d1272b8SAndroid Build Coastguard Worker const char *obj_start = (const char *) obj; 200*2d1272b8SAndroid Build Coastguard Worker if (unlikely (obj_start < this->start || this->end <= obj_start)) 201*2d1272b8SAndroid Build Coastguard Worker { 202*2d1272b8SAndroid Build Coastguard Worker this->start = this->end = nullptr; 203*2d1272b8SAndroid Build Coastguard Worker this->length = 0; 204*2d1272b8SAndroid Build Coastguard Worker } 205*2d1272b8SAndroid Build Coastguard Worker else 206*2d1272b8SAndroid Build Coastguard Worker { 207*2d1272b8SAndroid Build Coastguard Worker this->start = obj_start; 208*2d1272b8SAndroid Build Coastguard Worker this->end = obj_start + hb_min (size_t (this->end - obj_start), obj->get_size ()); 209*2d1272b8SAndroid Build Coastguard Worker this->length = this->end - this->start; 210*2d1272b8SAndroid Build Coastguard Worker } 211*2d1272b8SAndroid Build Coastguard Worker } 212*2d1272b8SAndroid Build Coastguard Worker reset_objecthb_sanitize_context_t213*2d1272b8SAndroid Build Coastguard Worker void reset_object () 214*2d1272b8SAndroid Build Coastguard Worker { 215*2d1272b8SAndroid Build Coastguard Worker this->start = this->blob->data; 216*2d1272b8SAndroid Build Coastguard Worker this->end = this->start + this->blob->length; 217*2d1272b8SAndroid Build Coastguard Worker this->length = this->end - this->start; 218*2d1272b8SAndroid Build Coastguard Worker assert (this->start <= this->end); /* Must not overflow. */ 219*2d1272b8SAndroid Build Coastguard Worker } 220*2d1272b8SAndroid Build Coastguard Worker start_processinghb_sanitize_context_t221*2d1272b8SAndroid Build Coastguard Worker void start_processing () 222*2d1272b8SAndroid Build Coastguard Worker { 223*2d1272b8SAndroid Build Coastguard Worker reset_object (); 224*2d1272b8SAndroid Build Coastguard Worker unsigned m; 225*2d1272b8SAndroid Build Coastguard Worker if (unlikely (hb_unsigned_mul_overflows (this->end - this->start, HB_SANITIZE_MAX_OPS_FACTOR, &m))) 226*2d1272b8SAndroid Build Coastguard Worker this->max_ops = HB_SANITIZE_MAX_OPS_MAX; 227*2d1272b8SAndroid Build Coastguard Worker else 228*2d1272b8SAndroid Build Coastguard Worker this->max_ops = hb_clamp (m, 229*2d1272b8SAndroid Build Coastguard Worker (unsigned) HB_SANITIZE_MAX_OPS_MIN, 230*2d1272b8SAndroid Build Coastguard Worker (unsigned) HB_SANITIZE_MAX_OPS_MAX); 231*2d1272b8SAndroid Build Coastguard Worker this->edit_count = 0; 232*2d1272b8SAndroid Build Coastguard Worker this->debug_depth = 0; 233*2d1272b8SAndroid Build Coastguard Worker this->recursion_depth = 0; 234*2d1272b8SAndroid Build Coastguard Worker 235*2d1272b8SAndroid Build Coastguard Worker DEBUG_MSG_LEVEL (SANITIZE, start, 0, +1, 236*2d1272b8SAndroid Build Coastguard Worker "start [%p..%p] (%lu bytes)", 237*2d1272b8SAndroid Build Coastguard Worker this->start, this->end, 238*2d1272b8SAndroid Build Coastguard Worker (unsigned long) (this->end - this->start)); 239*2d1272b8SAndroid Build Coastguard Worker } 240*2d1272b8SAndroid Build Coastguard Worker end_processinghb_sanitize_context_t241*2d1272b8SAndroid Build Coastguard Worker void end_processing () 242*2d1272b8SAndroid Build Coastguard Worker { 243*2d1272b8SAndroid Build Coastguard Worker DEBUG_MSG_LEVEL (SANITIZE, this->start, 0, -1, 244*2d1272b8SAndroid Build Coastguard Worker "end [%p..%p] %u edit requests", 245*2d1272b8SAndroid Build Coastguard Worker this->start, this->end, this->edit_count); 246*2d1272b8SAndroid Build Coastguard Worker 247*2d1272b8SAndroid Build Coastguard Worker hb_blob_destroy (this->blob); 248*2d1272b8SAndroid Build Coastguard Worker this->blob = nullptr; 249*2d1272b8SAndroid Build Coastguard Worker this->start = this->end = nullptr; 250*2d1272b8SAndroid Build Coastguard Worker this->length = 0; 251*2d1272b8SAndroid Build Coastguard Worker } 252*2d1272b8SAndroid Build Coastguard Worker get_edit_counthb_sanitize_context_t253*2d1272b8SAndroid Build Coastguard Worker unsigned get_edit_count () { return edit_count; } 254*2d1272b8SAndroid Build Coastguard Worker 255*2d1272b8SAndroid Build Coastguard Worker check_opshb_sanitize_context_t256*2d1272b8SAndroid Build Coastguard Worker bool check_ops(unsigned count) 257*2d1272b8SAndroid Build Coastguard Worker { 258*2d1272b8SAndroid Build Coastguard Worker /* Avoid underflow */ 259*2d1272b8SAndroid Build Coastguard Worker if (unlikely (this->max_ops < 0 || count >= (unsigned) this->max_ops)) 260*2d1272b8SAndroid Build Coastguard Worker { 261*2d1272b8SAndroid Build Coastguard Worker this->max_ops = -1; 262*2d1272b8SAndroid Build Coastguard Worker return false; 263*2d1272b8SAndroid Build Coastguard Worker } 264*2d1272b8SAndroid Build Coastguard Worker this->max_ops -= (int) count; 265*2d1272b8SAndroid Build Coastguard Worker return true; 266*2d1272b8SAndroid Build Coastguard Worker } 267*2d1272b8SAndroid Build Coastguard Worker 268*2d1272b8SAndroid Build Coastguard Worker #ifndef HB_OPTIMIZE_SIZE 269*2d1272b8SAndroid Build Coastguard Worker HB_ALWAYS_INLINE 270*2d1272b8SAndroid Build Coastguard Worker #endif check_rangehb_sanitize_context_t271*2d1272b8SAndroid Build Coastguard Worker bool check_range (const void *base, 272*2d1272b8SAndroid Build Coastguard Worker unsigned int len) const 273*2d1272b8SAndroid Build Coastguard Worker { 274*2d1272b8SAndroid Build Coastguard Worker const char *p = (const char *) base; 275*2d1272b8SAndroid Build Coastguard Worker bool ok = (uintptr_t) (p - this->start) <= this->length && 276*2d1272b8SAndroid Build Coastguard Worker (unsigned int) (this->end - p) >= len && 277*2d1272b8SAndroid Build Coastguard Worker ((this->max_ops -= len) > 0); 278*2d1272b8SAndroid Build Coastguard Worker 279*2d1272b8SAndroid Build Coastguard Worker DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0, 280*2d1272b8SAndroid Build Coastguard Worker "check_range [%p..%p]" 281*2d1272b8SAndroid Build Coastguard Worker " (%u bytes) in [%p..%p] -> %s", 282*2d1272b8SAndroid Build Coastguard Worker p, p + len, len, 283*2d1272b8SAndroid Build Coastguard Worker this->start, this->end, 284*2d1272b8SAndroid Build Coastguard Worker ok ? "OK" : "OUT-OF-RANGE"); 285*2d1272b8SAndroid Build Coastguard Worker 286*2d1272b8SAndroid Build Coastguard Worker return likely (ok); 287*2d1272b8SAndroid Build Coastguard Worker } 288*2d1272b8SAndroid Build Coastguard Worker #ifndef HB_OPTIMIZE_SIZE 289*2d1272b8SAndroid Build Coastguard Worker HB_ALWAYS_INLINE 290*2d1272b8SAndroid Build Coastguard Worker #endif check_range_fasthb_sanitize_context_t291*2d1272b8SAndroid Build Coastguard Worker bool check_range_fast (const void *base, 292*2d1272b8SAndroid Build Coastguard Worker unsigned int len) const 293*2d1272b8SAndroid Build Coastguard Worker { 294*2d1272b8SAndroid Build Coastguard Worker const char *p = (const char *) base; 295*2d1272b8SAndroid Build Coastguard Worker bool ok = ((uintptr_t) (p - this->start) <= this->length && 296*2d1272b8SAndroid Build Coastguard Worker (unsigned int) (this->end - p) >= len); 297*2d1272b8SAndroid Build Coastguard Worker 298*2d1272b8SAndroid Build Coastguard Worker DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0, 299*2d1272b8SAndroid Build Coastguard Worker "check_range_fast [%p..%p]" 300*2d1272b8SAndroid Build Coastguard Worker " (%u bytes) in [%p..%p] -> %s", 301*2d1272b8SAndroid Build Coastguard Worker p, p + len, len, 302*2d1272b8SAndroid Build Coastguard Worker this->start, this->end, 303*2d1272b8SAndroid Build Coastguard Worker ok ? "OK" : "OUT-OF-RANGE"); 304*2d1272b8SAndroid Build Coastguard Worker 305*2d1272b8SAndroid Build Coastguard Worker return likely (ok); 306*2d1272b8SAndroid Build Coastguard Worker } 307*2d1272b8SAndroid Build Coastguard Worker 308*2d1272b8SAndroid Build Coastguard Worker #ifndef HB_OPTIMIZE_SIZE 309*2d1272b8SAndroid Build Coastguard Worker HB_ALWAYS_INLINE 310*2d1272b8SAndroid Build Coastguard Worker #endif check_pointhb_sanitize_context_t311*2d1272b8SAndroid Build Coastguard Worker bool check_point (const void *base) const 312*2d1272b8SAndroid Build Coastguard Worker { 313*2d1272b8SAndroid Build Coastguard Worker const char *p = (const char *) base; 314*2d1272b8SAndroid Build Coastguard Worker bool ok = (uintptr_t) (p - this->start) <= this->length; 315*2d1272b8SAndroid Build Coastguard Worker 316*2d1272b8SAndroid Build Coastguard Worker DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0, 317*2d1272b8SAndroid Build Coastguard Worker "check_point [%p]" 318*2d1272b8SAndroid Build Coastguard Worker " in [%p..%p] -> %s", 319*2d1272b8SAndroid Build Coastguard Worker p, 320*2d1272b8SAndroid Build Coastguard Worker this->start, this->end, 321*2d1272b8SAndroid Build Coastguard Worker ok ? "OK" : "OUT-OF-RANGE"); 322*2d1272b8SAndroid Build Coastguard Worker 323*2d1272b8SAndroid Build Coastguard Worker return likely (ok); 324*2d1272b8SAndroid Build Coastguard Worker } 325*2d1272b8SAndroid Build Coastguard Worker 326*2d1272b8SAndroid Build Coastguard Worker template <typename T> check_rangehb_sanitize_context_t327*2d1272b8SAndroid Build Coastguard Worker bool check_range (const T *base, 328*2d1272b8SAndroid Build Coastguard Worker unsigned int a, 329*2d1272b8SAndroid Build Coastguard Worker unsigned int b) const 330*2d1272b8SAndroid Build Coastguard Worker { 331*2d1272b8SAndroid Build Coastguard Worker unsigned m; 332*2d1272b8SAndroid Build Coastguard Worker return !hb_unsigned_mul_overflows (a, b, &m) && 333*2d1272b8SAndroid Build Coastguard Worker this->check_range (base, m); 334*2d1272b8SAndroid Build Coastguard Worker } 335*2d1272b8SAndroid Build Coastguard Worker 336*2d1272b8SAndroid Build Coastguard Worker template <typename T> check_rangehb_sanitize_context_t337*2d1272b8SAndroid Build Coastguard Worker bool check_range (const T *base, 338*2d1272b8SAndroid Build Coastguard Worker unsigned int a, 339*2d1272b8SAndroid Build Coastguard Worker unsigned int b, 340*2d1272b8SAndroid Build Coastguard Worker unsigned int c) const 341*2d1272b8SAndroid Build Coastguard Worker { 342*2d1272b8SAndroid Build Coastguard Worker unsigned m; 343*2d1272b8SAndroid Build Coastguard Worker return !hb_unsigned_mul_overflows (a, b, &m) && 344*2d1272b8SAndroid Build Coastguard Worker this->check_range (base, m, c); 345*2d1272b8SAndroid Build Coastguard Worker } 346*2d1272b8SAndroid Build Coastguard Worker 347*2d1272b8SAndroid Build Coastguard Worker template <typename T> 348*2d1272b8SAndroid Build Coastguard Worker HB_ALWAYS_INLINE check_array_sizedhb_sanitize_context_t349*2d1272b8SAndroid Build Coastguard Worker bool check_array_sized (const T *base, unsigned int len, unsigned len_size) const 350*2d1272b8SAndroid Build Coastguard Worker { 351*2d1272b8SAndroid Build Coastguard Worker if (len_size >= 4) 352*2d1272b8SAndroid Build Coastguard Worker { 353*2d1272b8SAndroid Build Coastguard Worker if (unlikely (hb_unsigned_mul_overflows (len, hb_static_size (T), &len))) 354*2d1272b8SAndroid Build Coastguard Worker return false; 355*2d1272b8SAndroid Build Coastguard Worker } 356*2d1272b8SAndroid Build Coastguard Worker else 357*2d1272b8SAndroid Build Coastguard Worker len = len * hb_static_size (T); 358*2d1272b8SAndroid Build Coastguard Worker return this->check_range (base, len); 359*2d1272b8SAndroid Build Coastguard Worker } 360*2d1272b8SAndroid Build Coastguard Worker 361*2d1272b8SAndroid Build Coastguard Worker template <typename T> check_arrayhb_sanitize_context_t362*2d1272b8SAndroid Build Coastguard Worker bool check_array (const T *base, unsigned int len) const 363*2d1272b8SAndroid Build Coastguard Worker { 364*2d1272b8SAndroid Build Coastguard Worker return this->check_range (base, len, hb_static_size (T)); 365*2d1272b8SAndroid Build Coastguard Worker } 366*2d1272b8SAndroid Build Coastguard Worker 367*2d1272b8SAndroid Build Coastguard Worker template <typename T> check_arrayhb_sanitize_context_t368*2d1272b8SAndroid Build Coastguard Worker bool check_array (const T *base, 369*2d1272b8SAndroid Build Coastguard Worker unsigned int a, 370*2d1272b8SAndroid Build Coastguard Worker unsigned int b) const 371*2d1272b8SAndroid Build Coastguard Worker { 372*2d1272b8SAndroid Build Coastguard Worker return this->check_range (base, hb_static_size (T), a, b); 373*2d1272b8SAndroid Build Coastguard Worker } 374*2d1272b8SAndroid Build Coastguard Worker check_start_recursionhb_sanitize_context_t375*2d1272b8SAndroid Build Coastguard Worker bool check_start_recursion (int max_depth) 376*2d1272b8SAndroid Build Coastguard Worker { 377*2d1272b8SAndroid Build Coastguard Worker if (unlikely (recursion_depth >= max_depth)) return false; 378*2d1272b8SAndroid Build Coastguard Worker return ++recursion_depth; 379*2d1272b8SAndroid Build Coastguard Worker } 380*2d1272b8SAndroid Build Coastguard Worker end_recursionhb_sanitize_context_t381*2d1272b8SAndroid Build Coastguard Worker bool end_recursion (bool result) 382*2d1272b8SAndroid Build Coastguard Worker { 383*2d1272b8SAndroid Build Coastguard Worker recursion_depth--; 384*2d1272b8SAndroid Build Coastguard Worker return result; 385*2d1272b8SAndroid Build Coastguard Worker } 386*2d1272b8SAndroid Build Coastguard Worker 387*2d1272b8SAndroid Build Coastguard Worker template <typename Type> 388*2d1272b8SAndroid Build Coastguard Worker #ifndef HB_OPTIMIZE_SIZE 389*2d1272b8SAndroid Build Coastguard Worker HB_ALWAYS_INLINE 390*2d1272b8SAndroid Build Coastguard Worker #endif check_structhb_sanitize_context_t391*2d1272b8SAndroid Build Coastguard Worker bool check_struct (const Type *obj) const 392*2d1272b8SAndroid Build Coastguard Worker { 393*2d1272b8SAndroid Build Coastguard Worker if (sizeof (uintptr_t) == sizeof (uint32_t)) 394*2d1272b8SAndroid Build Coastguard Worker return likely (this->check_range_fast (obj, obj->min_size)); 395*2d1272b8SAndroid Build Coastguard Worker else 396*2d1272b8SAndroid Build Coastguard Worker return likely (this->check_point ((const char *) obj + obj->min_size)); 397*2d1272b8SAndroid Build Coastguard Worker } 398*2d1272b8SAndroid Build Coastguard Worker may_edithb_sanitize_context_t399*2d1272b8SAndroid Build Coastguard Worker bool may_edit (const void *base, unsigned int len) 400*2d1272b8SAndroid Build Coastguard Worker { 401*2d1272b8SAndroid Build Coastguard Worker if (this->edit_count >= HB_SANITIZE_MAX_EDITS) 402*2d1272b8SAndroid Build Coastguard Worker return false; 403*2d1272b8SAndroid Build Coastguard Worker 404*2d1272b8SAndroid Build Coastguard Worker const char *p = (const char *) base; 405*2d1272b8SAndroid Build Coastguard Worker this->edit_count++; 406*2d1272b8SAndroid Build Coastguard Worker 407*2d1272b8SAndroid Build Coastguard Worker DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0, 408*2d1272b8SAndroid Build Coastguard Worker "may_edit(%u) [%p..%p] (%u bytes) in [%p..%p] -> %s", 409*2d1272b8SAndroid Build Coastguard Worker this->edit_count, 410*2d1272b8SAndroid Build Coastguard Worker p, p + len, len, 411*2d1272b8SAndroid Build Coastguard Worker this->start, this->end, 412*2d1272b8SAndroid Build Coastguard Worker this->writable ? "GRANTED" : "DENIED"); 413*2d1272b8SAndroid Build Coastguard Worker 414*2d1272b8SAndroid Build Coastguard Worker return this->writable; 415*2d1272b8SAndroid Build Coastguard Worker } 416*2d1272b8SAndroid Build Coastguard Worker 417*2d1272b8SAndroid Build Coastguard Worker template <typename Type, typename ValueType> try_sethb_sanitize_context_t418*2d1272b8SAndroid Build Coastguard Worker bool try_set (const Type *obj, const ValueType &v) 419*2d1272b8SAndroid Build Coastguard Worker { 420*2d1272b8SAndroid Build Coastguard Worker if (this->may_edit (obj, hb_static_size (Type))) 421*2d1272b8SAndroid Build Coastguard Worker { 422*2d1272b8SAndroid Build Coastguard Worker * const_cast<Type *> (obj) = v; 423*2d1272b8SAndroid Build Coastguard Worker return true; 424*2d1272b8SAndroid Build Coastguard Worker } 425*2d1272b8SAndroid Build Coastguard Worker return false; 426*2d1272b8SAndroid Build Coastguard Worker } 427*2d1272b8SAndroid Build Coastguard Worker 428*2d1272b8SAndroid Build Coastguard Worker template <typename Type> sanitize_blobhb_sanitize_context_t429*2d1272b8SAndroid Build Coastguard Worker hb_blob_t *sanitize_blob (hb_blob_t *blob) 430*2d1272b8SAndroid Build Coastguard Worker { 431*2d1272b8SAndroid Build Coastguard Worker bool sane; 432*2d1272b8SAndroid Build Coastguard Worker 433*2d1272b8SAndroid Build Coastguard Worker init (blob); 434*2d1272b8SAndroid Build Coastguard Worker 435*2d1272b8SAndroid Build Coastguard Worker retry: 436*2d1272b8SAndroid Build Coastguard Worker DEBUG_MSG_FUNC (SANITIZE, start, "start"); 437*2d1272b8SAndroid Build Coastguard Worker 438*2d1272b8SAndroid Build Coastguard Worker start_processing (); 439*2d1272b8SAndroid Build Coastguard Worker 440*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!start)) 441*2d1272b8SAndroid Build Coastguard Worker { 442*2d1272b8SAndroid Build Coastguard Worker end_processing (); 443*2d1272b8SAndroid Build Coastguard Worker return blob; 444*2d1272b8SAndroid Build Coastguard Worker } 445*2d1272b8SAndroid Build Coastguard Worker 446*2d1272b8SAndroid Build Coastguard Worker Type *t = reinterpret_cast<Type *> (const_cast<char *> (start)); 447*2d1272b8SAndroid Build Coastguard Worker 448*2d1272b8SAndroid Build Coastguard Worker sane = t->sanitize (this); 449*2d1272b8SAndroid Build Coastguard Worker if (sane) 450*2d1272b8SAndroid Build Coastguard Worker { 451*2d1272b8SAndroid Build Coastguard Worker if (edit_count) 452*2d1272b8SAndroid Build Coastguard Worker { 453*2d1272b8SAndroid Build Coastguard Worker DEBUG_MSG_FUNC (SANITIZE, start, "passed first round with %u edits; going for second round", edit_count); 454*2d1272b8SAndroid Build Coastguard Worker 455*2d1272b8SAndroid Build Coastguard Worker /* sanitize again to ensure no toe-stepping */ 456*2d1272b8SAndroid Build Coastguard Worker edit_count = 0; 457*2d1272b8SAndroid Build Coastguard Worker sane = t->sanitize (this); 458*2d1272b8SAndroid Build Coastguard Worker if (edit_count) { 459*2d1272b8SAndroid Build Coastguard Worker DEBUG_MSG_FUNC (SANITIZE, start, "requested %u edits in second round; FAILING", edit_count); 460*2d1272b8SAndroid Build Coastguard Worker sane = false; 461*2d1272b8SAndroid Build Coastguard Worker } 462*2d1272b8SAndroid Build Coastguard Worker } 463*2d1272b8SAndroid Build Coastguard Worker } 464*2d1272b8SAndroid Build Coastguard Worker else 465*2d1272b8SAndroid Build Coastguard Worker { 466*2d1272b8SAndroid Build Coastguard Worker if (edit_count && !writable) { 467*2d1272b8SAndroid Build Coastguard Worker start = hb_blob_get_data_writable (blob, nullptr); 468*2d1272b8SAndroid Build Coastguard Worker end = start + blob->length; 469*2d1272b8SAndroid Build Coastguard Worker 470*2d1272b8SAndroid Build Coastguard Worker if (start) 471*2d1272b8SAndroid Build Coastguard Worker { 472*2d1272b8SAndroid Build Coastguard Worker writable = true; 473*2d1272b8SAndroid Build Coastguard Worker /* ok, we made it writable by relocating. try again */ 474*2d1272b8SAndroid Build Coastguard Worker DEBUG_MSG_FUNC (SANITIZE, start, "retry"); 475*2d1272b8SAndroid Build Coastguard Worker goto retry; 476*2d1272b8SAndroid Build Coastguard Worker } 477*2d1272b8SAndroid Build Coastguard Worker } 478*2d1272b8SAndroid Build Coastguard Worker } 479*2d1272b8SAndroid Build Coastguard Worker 480*2d1272b8SAndroid Build Coastguard Worker end_processing (); 481*2d1272b8SAndroid Build Coastguard Worker 482*2d1272b8SAndroid Build Coastguard Worker DEBUG_MSG_FUNC (SANITIZE, start, sane ? "PASSED" : "FAILED"); 483*2d1272b8SAndroid Build Coastguard Worker if (sane) 484*2d1272b8SAndroid Build Coastguard Worker { 485*2d1272b8SAndroid Build Coastguard Worker hb_blob_make_immutable (blob); 486*2d1272b8SAndroid Build Coastguard Worker return blob; 487*2d1272b8SAndroid Build Coastguard Worker } 488*2d1272b8SAndroid Build Coastguard Worker else 489*2d1272b8SAndroid Build Coastguard Worker { 490*2d1272b8SAndroid Build Coastguard Worker hb_blob_destroy (blob); 491*2d1272b8SAndroid Build Coastguard Worker return hb_blob_get_empty (); 492*2d1272b8SAndroid Build Coastguard Worker } 493*2d1272b8SAndroid Build Coastguard Worker } 494*2d1272b8SAndroid Build Coastguard Worker 495*2d1272b8SAndroid Build Coastguard Worker template <typename Type> reference_tablehb_sanitize_context_t496*2d1272b8SAndroid Build Coastguard Worker hb_blob_t *reference_table (const hb_face_t *face, hb_tag_t tableTag = Type::tableTag) 497*2d1272b8SAndroid Build Coastguard Worker { 498*2d1272b8SAndroid Build Coastguard Worker if (!num_glyphs_set) 499*2d1272b8SAndroid Build Coastguard Worker set_num_glyphs (hb_face_get_glyph_count (face)); 500*2d1272b8SAndroid Build Coastguard Worker return sanitize_blob<Type> (hb_face_reference_table (face, tableTag)); 501*2d1272b8SAndroid Build Coastguard Worker } 502*2d1272b8SAndroid Build Coastguard Worker 503*2d1272b8SAndroid Build Coastguard Worker const char *start, *end; 504*2d1272b8SAndroid Build Coastguard Worker unsigned length; 505*2d1272b8SAndroid Build Coastguard Worker mutable int max_ops, max_subtables; 506*2d1272b8SAndroid Build Coastguard Worker private: 507*2d1272b8SAndroid Build Coastguard Worker int recursion_depth; 508*2d1272b8SAndroid Build Coastguard Worker bool writable; 509*2d1272b8SAndroid Build Coastguard Worker unsigned int edit_count; 510*2d1272b8SAndroid Build Coastguard Worker hb_blob_t *blob; 511*2d1272b8SAndroid Build Coastguard Worker unsigned int num_glyphs; 512*2d1272b8SAndroid Build Coastguard Worker bool num_glyphs_set; 513*2d1272b8SAndroid Build Coastguard Worker public: 514*2d1272b8SAndroid Build Coastguard Worker bool lazy_some_gpos; 515*2d1272b8SAndroid Build Coastguard Worker }; 516*2d1272b8SAndroid Build Coastguard Worker 517*2d1272b8SAndroid Build Coastguard Worker struct hb_sanitize_with_object_t 518*2d1272b8SAndroid Build Coastguard Worker { 519*2d1272b8SAndroid Build Coastguard Worker template <typename T> hb_sanitize_with_object_thb_sanitize_with_object_t520*2d1272b8SAndroid Build Coastguard Worker hb_sanitize_with_object_t (hb_sanitize_context_t *c, const T& obj) : c (c) 521*2d1272b8SAndroid Build Coastguard Worker { c->set_object (obj); } ~hb_sanitize_with_object_thb_sanitize_with_object_t522*2d1272b8SAndroid Build Coastguard Worker ~hb_sanitize_with_object_t () 523*2d1272b8SAndroid Build Coastguard Worker { c->reset_object (); } 524*2d1272b8SAndroid Build Coastguard Worker 525*2d1272b8SAndroid Build Coastguard Worker private: 526*2d1272b8SAndroid Build Coastguard Worker hb_sanitize_context_t *c; 527*2d1272b8SAndroid Build Coastguard Worker }; 528*2d1272b8SAndroid Build Coastguard Worker 529*2d1272b8SAndroid Build Coastguard Worker 530*2d1272b8SAndroid Build Coastguard Worker #endif /* HB_SANITIZE_HH */ 531