summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Wagner <bungeman@google.com>2021-04-01 04:31:00 +0200
committerMichael BrĂ¼ning <michael.bruning@qt.io>2021-05-14 09:09:31 +0000
commit3e0b0ec3e4080feecaf82e2e99a3e1e17bb82b3d (patch)
treed100847510b8a09aff5b7392c3b94a2d75031b55
parent766902fc6744b2526270f5fac33a622af01495c5 (diff)
downloadqtwebengine-chromium-3e0b0ec3e4080feecaf82e2e99a3e1e17bb82b3d.tar.gz
[Backport] Security bug 1190525
Manual backport of patch originally submitted as https://gitlab.freedesktop.org/freetype/freetype/-/merge_requests/23/commits?commit_id=fb1beb00342d6905af5727b924ce6d8d80dcecaa: Prevent glyph program state from persisting FDEF instructions are specified as allowed only in 'prep' or 'fpgm'. FreeType has attempted to prevent their use in the glyph program, but they were still allowed in glyph program if defined in a function defined in 'prep' or 'fpgm' and called from the glyph program. Similarly, IDEF instructions are specified not to be able to modify any existing instruction. FreeType has attempted to prevent their use in the glyph program, but they can still be used like FDEF. This change stores the initial bytecode range type and disallows the use of FDEF and IDEF while running the glyph program. Most other state is copied from the TT_Size into the execution context. However, it is possible for a glyph program to use WS to write to the storage area or WCVTP, WCVTF, and DELTAC1-3 to write to the control value table. Allowing any change to the global state from the glyph program is problematic as the outlines of any given glyph may change based on the order the glyphs are loaded or even how many times they are loaded. There exist fonts which write to the storage area or the control value table in the glyph program, so their use should not be an error. Possible solutions to using these in the glyph program are * ignore the writes. * value level copy on write, discard modified values when finished. * array level copy on write, discard the copy when finished. * array level copy up front. Ignoring the writes may break otherwise good uses. A full copy up front was implemented, but was quite heavy as even well behaved fonts required a full copy and the memory management that goes along with it. Value level copy on write could use less memory but requires a great deal more record keeping and complexity. This change implements array level copy on write. If any attempt is made to write to the control value table or the storage area when the initial bytecode range was in a glyph program then the relevant array will be copied to a designated storage area and the copy used for the rest of the glyph program's execution. Change-Id: I65887f866c37321744e59f2e64b80f2b056a11a7 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
-rw-r--r--chromium/third_party/freetype/src/src/truetype/ttgload.c2
-rw-r--r--chromium/third_party/freetype/src/src/truetype/ttinterp.c79
-rw-r--r--chromium/third_party/freetype/src/src/truetype/ttinterp.h11
3 files changed, 83 insertions, 9 deletions
diff --git a/chromium/third_party/freetype/src/src/truetype/ttgload.c b/chromium/third_party/freetype/src/src/truetype/ttgload.c
index f0f6a060275..e5d50474afc 100644
--- a/chromium/third_party/freetype/src/src/truetype/ttgload.c
+++ b/chromium/third_party/freetype/src/src/truetype/ttgload.c
@@ -425,7 +425,7 @@
(void*)&load->exec->glyphIns,
n_ins );
- load->exec->glyphSize = (FT_UShort)tmp;
+ load->exec->glyphSize = (FT_UInt)tmp;
if ( error )
return error;
diff --git a/chromium/third_party/freetype/src/src/truetype/ttinterp.c b/chromium/third_party/freetype/src/src/truetype/ttinterp.c
index da45c373a74..fb2e677101d 100644
--- a/chromium/third_party/freetype/src/src/truetype/ttinterp.c
+++ b/chromium/third_party/freetype/src/src/truetype/ttinterp.c
@@ -252,6 +252,14 @@
FT_FREE( exec->stack );
exec->stackSize = 0;
+ /* free glyf cvt working area */
+ FT_FREE( exec->glyfCvt );
+ exec->glyfCvtSize = 0;
+
+ /* free glyf storage working area */
+ FT_FREE( exec->glyfStorage );
+ exec->glyfStoreSize = 0;
+
/* free call stack */
FT_FREE( exec->callStack );
exec->callSize = 0;
@@ -465,13 +473,13 @@
if ( error )
return error;
- tmp = exec->glyphSize;
+ tmp = (FT_ULong)exec->glyphSize;
error = Update_Max( exec->memory,
&tmp,
sizeof ( FT_Byte ),
(void*)&exec->glyphIns,
maxp->maxSizeOfInstructions );
- exec->glyphSize = (FT_UShort)tmp;
+ exec->glyphSize = (FT_UInt)tmp;
if ( error )
return error;
@@ -1548,12 +1556,31 @@
return FT_MulFix( exc->cvt[idx], Current_Ratio( exc ) );
}
+ static void Modify_CVT_Check( TT_ExecContext exc ) {
+ /* TT_RunIns sets origCvt and restores cvt to origCvt when done. */
+ if ( exc->initialRange == tt_coderange_glyph && exc->cvt == exc->origCvt ) {
+ exc->error = Update_Max( exc->memory,
+ &exc->glyfCvtSize,
+ sizeof ( FT_Long ),
+ (void*)&exc->glyfCvt,
+ exc->cvtSize );
+ if ( exc->error )
+ return;
+
+ FT_ARRAY_COPY( exc->glyfCvt, exc->cvt, exc->glyfCvtSize );
+ exc->cvt = exc->glyfCvt;
+ }
+ }
FT_CALLBACK_DEF( void )
Write_CVT( TT_ExecContext exc,
FT_ULong idx,
FT_F26Dot6 value )
{
+ Modify_CVT_Check( exc );
+ if ( exc->error )
+ return;
+
exc->cvt[idx] = value;
}
@@ -1563,6 +1590,10 @@
FT_ULong idx,
FT_F26Dot6 value )
{
+ Modify_CVT_Check( exc );
+ if ( exc->error )
+ return;
+
exc->cvt[idx] = FT_DivFix( value, Current_Ratio( exc ) );
}
@@ -1572,6 +1603,10 @@
FT_ULong idx,
FT_F26Dot6 value )
{
+ Modify_CVT_Check( exc );
+ if ( exc->error )
+ return;
+
exc->cvt[idx] += value;
}
@@ -1581,6 +1616,10 @@
FT_ULong idx,
FT_F26Dot6 value )
{
+ Modify_CVT_Check( exc );
+ if ( exc->error )
+ return;
+
exc->cvt[idx] += FT_DivFix( value, Current_Ratio( exc ) );
}
@@ -3086,7 +3125,25 @@
ARRAY_BOUND_ERROR;
}
else
+ {
+ /* TT_RunIns sets origStorage and restores storage to origStorage when done. */
+ if ( exc->initialRange == tt_coderange_glyph && exc->storage == exc->origStorage ) {
+ FT_ULong tmp = (FT_ULong)exc->glyfStoreSize;
+ exc->error = Update_Max( exc->memory,
+ &tmp,
+ sizeof ( FT_Long ),
+ (void*)&exc->glyfStorage,
+ exc->storeSize );
+ exc->glyfStoreSize = (FT_UShort)tmp;
+ if ( exc->error )
+ return;
+
+ FT_ARRAY_COPY( exc->glyfStorage, exc->storage, exc->glyfStoreSize );
+ exc->storage = exc->glyfStorage;
+ }
+
exc->storage[I] = args[1];
+ }
}
@@ -3664,7 +3721,7 @@
/* FDEF is only allowed in `prep' or `fpgm' */
- if ( exc->curRange == tt_coderange_glyph )
+ if ( exc->initialRange == tt_coderange_glyph )
{
exc->error = FT_THROW( DEF_In_Glyf_Bytecode );
return;
@@ -4097,7 +4154,7 @@
/* we enable IDEF only in `prep' or `fpgm' */
- if ( exc->curRange == tt_coderange_glyph )
+ if ( exc->initialRange == tt_coderange_glyph )
{
exc->error = FT_THROW( DEF_In_Glyf_Bytecode );
return;
@@ -7856,6 +7913,9 @@
exc->func_write_cvt = Write_CVT;
exc->func_move_cvt = Move_CVT;
}
+ exc->origCvt = exc->cvt;
+ exc->origStorage = exc->storage;
+ exc->initialRange = exc->curRange;
Compute_Funcs( exc );
Compute_Round( exc, (FT_Byte)exc->GS.round_state );
@@ -8581,8 +8641,10 @@
/* increment instruction counter and check if we didn't */
/* run this program for too long (e.g. infinite loops). */
- if ( ++ins_counter > TT_CONFIG_OPTION_MAX_RUNNABLE_OPCODES )
- return FT_THROW( Execution_Too_Long );
+ if ( ++ins_counter > TT_CONFIG_OPTION_MAX_RUNNABLE_OPCODES ) {
+ exc->error = FT_THROW( Execution_Too_Long );
+ goto LErrorLabel_;
+ }
LSuiteLabel_:
if ( exc->IP >= exc->codeSize )
@@ -8601,6 +8663,9 @@
FT_TRACE4(( " %d instruction%s executed\n",
ins_counter,
ins_counter == 1 ? "" : "s" ));
+
+ exc->cvt = exc->origCvt;
+ exc->storage = exc->origStorage;
return FT_Err_Ok;
LErrorCodeOverflow_:
@@ -8610,6 +8675,8 @@
if ( exc->error && !exc->instruction_trap )
FT_TRACE1(( " The interpreter returned error 0x%x\n", exc->error ));
+ exc->cvt = exc->origCvt;
+ exc->storage = exc->origStorage;
return exc->error;
}
diff --git a/chromium/third_party/freetype/src/src/truetype/ttinterp.h b/chromium/third_party/freetype/src/src/truetype/ttinterp.h
index 172cdd0287d..1d149215603 100644
--- a/chromium/third_party/freetype/src/src/truetype/ttinterp.h
+++ b/chromium/third_party/freetype/src/src/truetype/ttinterp.h
@@ -175,6 +175,7 @@ FT_BEGIN_HEADER
TT_Size_Metrics tt_metrics; /* size metrics */
TT_GraphicsState GS; /* current graphics state */
+ FT_Int initialRange; /* initial code range number */
FT_Int curRange; /* current code range number */
FT_Byte* code; /* current code range */
@@ -188,6 +189,9 @@ FT_BEGIN_HEADER
/* increment IP after ins. exec */
FT_ULong cvtSize;
FT_Long* cvt;
+ FT_ULong glyfCvtSize;
+ FT_Long* glyfCvt; /* cvt working copy for glyph */
+ FT_Long* origCvt;
FT_UInt glyphSize; /* glyph instructions buffer size */
FT_Byte* glyphIns; /* glyph instructions buffer */
@@ -214,8 +218,11 @@ FT_BEGIN_HEADER
TT_CodeRangeTable codeRangeTable; /* table of valid code ranges */
/* useful for the debugger */
- FT_UShort storeSize; /* size of current storage */
- FT_Long* storage; /* storage area */
+ FT_UShort storeSize; /* size of current storage */
+ FT_Long* storage; /* storage area */
+ FT_UShort glyfStoreSize;
+ FT_Long* glyfStorage; /* storage working copy for glyph */
+ FT_Long* origStorage;
FT_F26Dot6 period; /* values used for the */
FT_F26Dot6 phase; /* `SuperRounding' */