[CFF] oss-fuzz issue 11690 ASSERT: substr.offset >= opStart (#1461)

* fix oss-fuzz 11690: substr.offset >= opStart

detect recursive subroutine call & handle as error

* fix build failure

* add minimized test case for oss-fuzz 11690

* removed asserts
This commit is contained in:
Michiharu Ariza 2018-12-11 12:21:24 -08:00 committed by Behdad Esfahbod
parent 333586245c
commit 2941208f1e
5 changed files with 18 additions and 11 deletions

View File

@ -332,8 +332,10 @@ struct ByteStr
inline bool sanitize (hb_sanitize_context_t *c) const { return str->sanitize (c, len); } inline bool sanitize (hb_sanitize_context_t *c) const { return str->sanitize (c, len); }
inline const HBUINT8& operator [] (unsigned int i) const { inline const HBUINT8& operator [] (unsigned int i) const {
assert (str && (i < len)); if (likely (str && (i < len)))
return (*str)[i]; return (*str)[i];
else
return Null(HBUINT8);
} }
inline bool serialize (hb_serialize_context_t *c, const ByteStr &src) inline bool serialize (hb_serialize_context_t *c, const ByteStr &src)
@ -628,7 +630,6 @@ struct ParsedValues
{ {
VAL *val = values.push (); VAL *val = values.push ();
val->op = op; val->op = op;
assert (substr.offset >= opStart);
val->str = ByteStr (substr.str, opStart, substr.offset - opStart); val->str = ByteStr (substr.str, opStart, substr.offset - opStart);
opStart = substr.offset; opStart = substr.offset;
} }
@ -637,7 +638,6 @@ struct ParsedValues
{ {
VAL *val = values.push (v); VAL *val = values.push (v);
val->op = op; val->op = op;
assert (substr.offset >= opStart);
val->str = ByteStr (substr.str, opStart, substr.offset - opStart); val->str = ByteStr (substr.str, opStart, substr.offset - opStart);
opStart = substr.offset; opStart = substr.offset;
} }
@ -707,7 +707,6 @@ struct InterpEnv
inline void pop_n_args (unsigned int n) inline void pop_n_args (unsigned int n)
{ {
assert (n <= argStack.get_count ());
argStack.pop (n); argStack.pop (n);
} }

View File

@ -526,11 +526,19 @@ struct SubrSubsetParam
} }
template <typename ENV> template <typename ENV>
inline void set_current_str (ENV &env) inline void set_current_str (ENV &env, bool calling)
{ {
ParsedCStr *parsed_str = get_parsed_str_for_context (env.context); ParsedCStr *parsed_str = get_parsed_str_for_context (env.context);
if (likely (parsed_str != nullptr)) if (likely (parsed_str != nullptr))
{
/* If the called subroutine is parsed partially but not completely yet,
* it must be because we are calling it recursively.
* Handle it as an error. */
if (unlikely (calling && !parsed_str->is_parsed () && (parsed_str->values.len > 0)))
env.set_error ();
else
current_parsed_str = parsed_str; current_parsed_str = parsed_str;
}
else else
env.set_error (); env.set_error ();
} }

View File

@ -362,7 +362,7 @@ struct CFF1CSOpSet_SubrSubset : CFF1CSOpSet<CFF1CSOpSet_SubrSubset, SubrSubsetPa
param.current_parsed_str->add_op (op, env.substr); param.current_parsed_str->add_op (op, env.substr);
param.current_parsed_str->set_parsed (); param.current_parsed_str->set_parsed ();
env.returnFromSubr (); env.returnFromSubr ();
param.set_current_str (env); param.set_current_str (env, false);
break; break;
case OpCode_endchar: case OpCode_endchar:
@ -395,7 +395,7 @@ struct CFF1CSOpSet_SubrSubset : CFF1CSOpSet<CFF1CSOpSet_SubrSubset, SubrSubsetPa
env.callSubr (subrs, type); env.callSubr (subrs, type);
param.current_parsed_str->add_call_op (op, substr, env.context.subr_num); param.current_parsed_str->add_call_op (op, substr, env.context.subr_num);
hb_set_add (closure, env.context.subr_num); hb_set_add (closure, env.context.subr_num);
param.set_current_str (env); param.set_current_str (env, true);
} }
private: private:

View File

@ -184,7 +184,7 @@ struct CFF2CSOpSet_SubrSubset : CFF2CSOpSet<CFF2CSOpSet_SubrSubset, SubrSubsetPa
case OpCode_return: case OpCode_return:
param.current_parsed_str->set_parsed (); param.current_parsed_str->set_parsed ();
env.returnFromSubr (); env.returnFromSubr ();
param.set_current_str (env); param.set_current_str (env, false);
break; break;
case OpCode_endchar: case OpCode_endchar:
@ -216,7 +216,7 @@ struct CFF2CSOpSet_SubrSubset : CFF2CSOpSet<CFF2CSOpSet_SubrSubset, SubrSubsetPa
env.callSubr (subrs, type); env.callSubr (subrs, type);
param.current_parsed_str->add_call_op (op, substr, env.context.subr_num); param.current_parsed_str->add_call_op (op, substr, env.context.subr_num);
hb_set_add (closure, env.context.subr_num); hb_set_add (closure, env.context.subr_num);
param.set_current_str (env); param.set_current_str (env, true);
} }
private: private: