Skip to content

Latest commit

 

History

History
64 lines (47 loc) · 5.53 KB

File metadata and controls

64 lines (47 loc) · 5.53 KB

CFF/CFF2 Security Review Report

Revision: 8 Timestamp: 2026-02-15 01:13:05 UTC

This document reviews the current security state of the CFF and CFF2 implementation in the PascalType2 library. The audit covers vulnerabilities identified in the Project Zero research "One font vulnerability to rule them all" and more recent industry findings.

Executive Summary

The PascalType2 CFF/CFF2 implementation is designed with security-first principles, utilizing managed types and explicit logical boundaries to prevent the memory corruption and stack exhaustion issues prevalent in legacy font engines. The implementation is verified to be resilient against all identified CharString and DICT parsing exploit vectors.

Bulletin / CVE Status Protection Mechanism
MS15-021 PASS Enforced recursion and stack limits; validated instruction stream bounds.
MS15-044 PASS Automated zero-initialization of transient memory.
APSB15-10 PASS Robust opcode validation and bounds-checked operands.
CVE-2020-0938 PASS Non-implementation of legacy Master design operators (BLEND).
CVE-2020-1020 PASS Isolated interpreter state prevents out-of-bounds stack manipulation.
CVE-2023-25193 PASS Variable font variation limits are inherently safe due to non-implementation of CFF2 variations.

Audit findings and Security Controls

1. Subroutine Recursion Control

  • CVEs: CVE-2015-0074
  • Status: PASS
  • Mechanism: The Interpret method in PascalType.Tables.OpenType.PostScript.CharStrings.pas enforces a strict recursion depth limit of 32 (CMaxRecursionDepth). This proactively prevents system stack exhaustion from recursive subroutine calls.

2. Instruction Stream Validation

  • CVEs: CVE-2015-0087, CVE-2015-3095
  • Status: PASS
  • Mechanism: The hintmask and cntrmask operators perform explicit bounds checks against the CharString byte array before advancing the instruction pointer, raising ECffHintMaskOverflow on violation. Furthermore, the BCD parser in DICT table loading validates stream positions to prevent infinite loops on malformed or unterminated data.

3. Operand Stack Safety

  • CVEs: CVE-2015-0088
  • Status: PASS
  • Mechanism: The interpreter utilizes a dynamic TList<Single> with a hard capacity limit of 192 elements (CMaxStackDepth), raising ECffStackOverflow if exceeded. All operations including Pop, index, and roll are guarded by bounds checks.

4. Memory Isolation

  • CVEs: CVE-2015-0089, CVE-2015-3049, CVE-2015-1670
  • Status: PASS
  • Mechanism: The FTransientArray is zero-initialized during interpreter setup. The get and put operators are strictly limited to the defined array bounds, preventing arbitrary memory access or disclosure.

5. Exclusion of Legacy Attack Surface

  • CVEs: CVE-2015-0090, CVE-2015-0092, CVE-2015-0093, CVE-2020-0938, CVE-2020-1020
  • Status: PASS (Protected by non-implementation)
  • Mechanism: Legacy and deprecated operators (LOAD, STORE, BLEND, STOREWV) are deliberately excluded from the implementation. Executing these opcodes in the PascalType2 interpreter result in a no-op (stack clear), eliminating the primary attack surface used for complex ROP-based exploits in historical vulnerabilities. Regression tests in Test/TestCFFSecurity.pas guard against accidental implementation of these vulnerable paths.

6. Error Handling

  • Status: PASS
  • Mechanism: The interpreter distinguishes between fatal logical errors and non-fatal warnings. Only exceptions of type EPascalTypeWarning are swallowed by the Execute method to allow for graceful degradation. Fatal EPascalTypeError exceptions bubble up, ensuring that security violations or severe corruption are explicitly handled.

Technical Appendix: Validation Opcodes

The following sequences are verified in Test/TestCFFSecurity.pas to ensure ongoing compliance with security boundaries.

  • Recursion: 20 0a 0e calls Subr 0 containing 20 0a 0b (Infinite recursion test). Verified to raise ECffMaxRecursion.
  • Stack Overflow: 8b ... 8b (Push > 192 elements test). Verified to raise ECffStackOverflow.
  • OOB Mask: 8b 8b 8b 8b 01 13 (Mask skip beyond EOB test). Verified to raise ECffHintMaskOverflow.
  • Unterminated DICT: 1e 12 34 (BCD parsing beyond DICT size test). Verified to raise EPascalTypeError.
  • Unimplemented Operators: Opcode 16 (BLEND), Escape 13 (LOAD), Escape 16 (callothersubr), etc. Verified to be safe (no-op/stack clear).