From 5a7c371e4c6f1775ebbfe120fafe92afe402a954 Mon Sep 17 00:00:00 2001 From: Michiharu Ariza Date: Tue, 4 Dec 2018 22:24:38 -0800 Subject: [PATCH 01/11] check overflow & clamp --- src/hb-cff-interp-dict-common.hh | 36 ++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/src/hb-cff-interp-dict-common.hh b/src/hb-cff-interp-dict-common.hh index 2822af40c..62c87e94a 100644 --- a/src/hb-cff-interp-dict-common.hh +++ b/src/hb-cff-interp-dict-common.hh @@ -105,16 +105,17 @@ struct DictOpSet : OpSet static inline double parse_bcd (SubByteStr& substr) { - double v = 0.0; - bool neg = false; double int_part = 0; long frac_part = 0; unsigned int frac_count = 0; bool exp_neg = false; unsigned int exp_part = 0; + bool exp_overflow = false; enum Part { INT_PART=0, FRAC_PART, EXP_PART } part = INT_PART; enum Nibble { DECIMAL=10, EXP_POS, EXP_NEG, RESERVED, NEG, END }; + const unsigned long MAX_FRACT = 0xFFFFFFFFFFFFFlu; /* 1^52-1 */ + const unsigned int MAX_EXP = 0x7FFu; /* 1^11-1 */ double value = 0.0; unsigned char byte = 0; @@ -139,12 +140,21 @@ struct DictOpSet : OpSet { case RESERVED: substr.set_error (); - return v; + return value; case END: value = (double)(neg? -int_part: int_part); if (frac_count > 0) value += (frac_part / pow (10.0, (double)frac_count)); + if (unlikely (exp_overflow)) + { + if (value == 0.0) + return value; + if (exp_neg) + return neg? -DBL_MIN: DBL_MIN; + else + return neg? -DBL_MAX: DBL_MAX; + } if (exp_part != 0) { if (exp_neg) @@ -167,7 +177,7 @@ struct DictOpSet : OpSet if (part != INT_PART) { substr.set_error (); - return v; + return value; } part = FRAC_PART; break; @@ -180,7 +190,7 @@ struct DictOpSet : OpSet if (part == EXP_PART) { substr.set_error (); - return v; + return value; } part = EXP_PART; break; @@ -193,18 +203,26 @@ struct DictOpSet : OpSet break; case FRAC_PART: - frac_part = (frac_part * 10) + d; - frac_count++; + if (likely ((fract_count <= MAX_FRACT / 10))) + { + frac_part = (frac_part * 10) + d; + frac_count++; + } break; case EXP_PART: - exp_part = (exp_part * 10) + d; + if (likely (exp_part * 10) + d <= MAX_EXP) + { + exp_part = (exp_part * 10) + d; + } + else + exp_overflow = true; break; } } } - return v; + return value; } static inline bool is_hint_op (OpCode op) From 85d4b15cd88ce9a6ffccccf90300f9c184166058 Mon Sep 17 00:00:00 2001 From: Michiharu Ariza Date: Tue, 4 Dec 2018 22:30:33 -0800 Subject: [PATCH 02/11] include float.h --- src/hb-cff-interp-dict-common.hh | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hb-cff-interp-dict-common.hh b/src/hb-cff-interp-dict-common.hh index 62c87e94a..ace91bea4 100644 --- a/src/hb-cff-interp-dict-common.hh +++ b/src/hb-cff-interp-dict-common.hh @@ -28,6 +28,7 @@ #include "hb-cff-interp-common.hh" #include +#include namespace CFF { From 0e81b153aff1f2e301e73ca1a15a9bc5b2e7bb82 Mon Sep 17 00:00:00 2001 From: Michiharu Ariza Date: Tue, 4 Dec 2018 22:40:07 -0800 Subject: [PATCH 03/11] fix typo --- src/hb-cff-interp-dict-common.hh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hb-cff-interp-dict-common.hh b/src/hb-cff-interp-dict-common.hh index ace91bea4..7eafc7c08 100644 --- a/src/hb-cff-interp-dict-common.hh +++ b/src/hb-cff-interp-dict-common.hh @@ -204,7 +204,7 @@ struct DictOpSet : OpSet break; case FRAC_PART: - if (likely ((fract_count <= MAX_FRACT / 10))) + if (likely ((frac_count <= MAX_FRACT / 10))) { frac_part = (frac_part * 10) + d; frac_count++; From 755fefc92113e469a1aadee2546958fede156c01 Mon Sep 17 00:00:00 2001 From: Michiharu Ariza Date: Tue, 4 Dec 2018 23:18:28 -0800 Subject: [PATCH 04/11] fix bug --- src/hb-cff-interp-dict-common.hh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hb-cff-interp-dict-common.hh b/src/hb-cff-interp-dict-common.hh index 7eafc7c08..f84f26cd4 100644 --- a/src/hb-cff-interp-dict-common.hh +++ b/src/hb-cff-interp-dict-common.hh @@ -204,7 +204,7 @@ struct DictOpSet : OpSet break; case FRAC_PART: - if (likely ((frac_count <= MAX_FRACT / 10))) + if (likely ((fract_part <= MAX_FRACT / 10))) { frac_part = (frac_part * 10) + d; frac_count++; From c01a5f32a33fa875de68ca29a4672fd36a05245b Mon Sep 17 00:00:00 2001 From: Michiharu Ariza Date: Tue, 4 Dec 2018 23:23:23 -0800 Subject: [PATCH 05/11] refix --- src/hb-cff-interp-dict-common.hh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hb-cff-interp-dict-common.hh b/src/hb-cff-interp-dict-common.hh index f84f26cd4..0ffd4cecc 100644 --- a/src/hb-cff-interp-dict-common.hh +++ b/src/hb-cff-interp-dict-common.hh @@ -204,7 +204,7 @@ struct DictOpSet : OpSet break; case FRAC_PART: - if (likely ((fract_part <= MAX_FRACT / 10))) + if (likely ((frac_part <= MAX_FRACT / 10))) { frac_part = (frac_part * 10) + d; frac_count++; From f9cee08edd32182044407bf6ffde00df0feb09b7 Mon Sep 17 00:00:00 2001 From: Michiharu Ariza Date: Tue, 4 Dec 2018 23:58:26 -0800 Subject: [PATCH 06/11] use sized int types in parse_bcd --- src/hb-cff-interp-dict-common.hh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/hb-cff-interp-dict-common.hh b/src/hb-cff-interp-dict-common.hh index 0ffd4cecc..d5376e842 100644 --- a/src/hb-cff-interp-dict-common.hh +++ b/src/hb-cff-interp-dict-common.hh @@ -108,19 +108,19 @@ struct DictOpSet : OpSet { bool neg = false; double int_part = 0; - long frac_part = 0; - unsigned int frac_count = 0; + int64_t frac_part = 0; + uint32_t frac_count = 0; bool exp_neg = false; - unsigned int exp_part = 0; + uint32_t exp_part = 0; bool exp_overflow = false; enum Part { INT_PART=0, FRAC_PART, EXP_PART } part = INT_PART; enum Nibble { DECIMAL=10, EXP_POS, EXP_NEG, RESERVED, NEG, END }; - const unsigned long MAX_FRACT = 0xFFFFFFFFFFFFFlu; /* 1^52-1 */ - const unsigned int MAX_EXP = 0x7FFu; /* 1^11-1 */ + const uint64_t MAX_FRACT = 0xFFFFFFFFFFFFFlu; /* 1^52-1 */ + const uint32_t MAX_EXP = 0x7FFu; /* 1^11-1 */ double value = 0.0; unsigned char byte = 0; - for (unsigned int i = 0;; i++) + for (uint32_t i = 0;; i++) { char d; if ((i & 1) == 0) From 28dfb4c14280b05ad0a519f9df2b0eda41a62540 Mon Sep 17 00:00:00 2001 From: Michiharu Ariza Date: Wed, 5 Dec 2018 00:26:03 -0800 Subject: [PATCH 07/11] fix signed/unsigned comparison --- src/hb-cff-interp-dict-common.hh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hb-cff-interp-dict-common.hh b/src/hb-cff-interp-dict-common.hh index d5376e842..2c7a9710a 100644 --- a/src/hb-cff-interp-dict-common.hh +++ b/src/hb-cff-interp-dict-common.hh @@ -108,7 +108,7 @@ struct DictOpSet : OpSet { bool neg = false; double int_part = 0; - int64_t frac_part = 0; + uint64_t frac_part = 0; uint32_t frac_count = 0; bool exp_neg = false; uint32_t exp_part = 0; @@ -206,7 +206,7 @@ struct DictOpSet : OpSet case FRAC_PART: if (likely ((frac_part <= MAX_FRACT / 10))) { - frac_part = (frac_part * 10) + d; + frac_part = (frac_part * 10) + (unsigned)d; frac_count++; } break; From 620d1ef588c6ce25644891cfe4b9c20fd8a9d1db Mon Sep 17 00:00:00 2001 From: Michiharu Ariza Date: Wed, 5 Dec 2018 00:36:11 -0800 Subject: [PATCH 08/11] fix unsigned long const --- src/hb-cff-interp-dict-common.hh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hb-cff-interp-dict-common.hh b/src/hb-cff-interp-dict-common.hh index 2c7a9710a..005e15e60 100644 --- a/src/hb-cff-interp-dict-common.hh +++ b/src/hb-cff-interp-dict-common.hh @@ -115,7 +115,7 @@ struct DictOpSet : OpSet bool exp_overflow = false; enum Part { INT_PART=0, FRAC_PART, EXP_PART } part = INT_PART; enum Nibble { DECIMAL=10, EXP_POS, EXP_NEG, RESERVED, NEG, END }; - const uint64_t MAX_FRACT = 0xFFFFFFFFFFFFFlu; /* 1^52-1 */ + const uint64_t MAX_FRACT = 0xFFFFFFFFFFFFFllu; /* 1^52-1 */ const uint32_t MAX_EXP = 0x7FFu; /* 1^11-1 */ double value = 0.0; From a5fa843c746e20aaca48ece6cff057deb8d916ca Mon Sep 17 00:00:00 2001 From: Michiharu Ariza Date: Wed, 5 Dec 2018 11:18:16 -0800 Subject: [PATCH 09/11] fixed a bug with fractional part in a negative value --- src/hb-cff-interp-dict-common.hh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/hb-cff-interp-dict-common.hh b/src/hb-cff-interp-dict-common.hh index 005e15e60..63ca685ec 100644 --- a/src/hb-cff-interp-dict-common.hh +++ b/src/hb-cff-interp-dict-common.hh @@ -146,7 +146,11 @@ struct DictOpSet : OpSet case END: value = (double)(neg? -int_part: int_part); if (frac_count > 0) - value += (frac_part / pow (10.0, (double)frac_count)); + { + double frac = (frac_part / pow (10.0, (double)frac_count)); + if (neg) frac = -frac; + value += frac; + } if (unlikely (exp_overflow)) { if (value == 0.0) From 010e2ddb384b5a721172fd7466aafec58dbf8063 Mon Sep 17 00:00:00 2001 From: Michiharu Ariza Date: Wed, 5 Dec 2018 12:23:58 -0800 Subject: [PATCH 10/11] minimized test case for oss-fuzz issue 11674 --- ...ase-minimized-hb-subset-fuzzer-5672006905757696 | Bin 0 -> 73 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5672006905757696 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5672006905757696 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5672006905757696 new file mode 100644 index 0000000000000000000000000000000000000000..cb5fb83da5ca7f82d906143ea81bc6029a9287b6 GIT binary patch literal 73 scmeYd3GruOQ~(2KH#acNz`!62W-u}^GAb}IvH%4bA%b#U5T%$T07)GPVgLXD literal 0 HcmV?d00001 From 6708c5595fc6babdae0132f8a23cbe3558a58703 Mon Sep 17 00:00:00 2001 From: Michiharu Ariza Date: Wed, 5 Dec 2018 12:51:18 -0800 Subject: [PATCH 11/11] fix oss-fuzz issue 11675 (ASSERT: count <= str.len) Also added an additional error check to avail () --- src/hb-cff-interp-common.hh | 18 ++++++++++++++++-- ...inimized-hb-subset-fuzzer-5768186323009536 | Bin 0 -> 337 bytes 2 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5768186323009536 diff --git a/src/hb-cff-interp-common.hh b/src/hb-cff-interp-common.hh index f2ccc2bdd..9b595ff1a 100644 --- a/src/hb-cff-interp-common.hh +++ b/src/hb-cff-interp-common.hh @@ -391,8 +391,22 @@ struct SubByteStr inline operator ByteStr (void) const { return ByteStr (str, offset, str.len - offset); } - inline bool avail (unsigned int count=1) const { return str.check_limit (offset, count); } - inline void inc (unsigned int count=1) { offset += count; assert (count <= str.len); } + inline bool avail (unsigned int count=1) const + { + return (!in_error () && str.check_limit (offset, count)); + } + inline void inc (unsigned int count=1) + { + if (likely (!in_error () && (offset <= str.len) && (offset + count <= str.len))) + { + offset += count; + } + else + { + offset = str.len; + set_error (); + } + } inline void set_error (void) { error = true; } inline bool in_error (void) const { return error; } diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5768186323009536 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5768186323009536 new file mode 100644 index 0000000000000000000000000000000000000000..858604d717650226cc56864063bb778518f6233b GIT binary patch literal 337 zcmeYd3Grv(Qvd^JH#acNz`)1|5kV#YqjC|v|4@Js!OFs^AFFCQ2{M8_3&gJO)UZ%i F0RU6-GRgn| literal 0 HcmV?d00001