New issue
Advanced search Search tips
Starred by 3 users

Issue metadata

Status: Fixed
Closed: Jul 2015

Sign in to add a comment

Issue 281: Oracle Java Runtime Environment memory disclosure via uninitialized transient array

Reported by, Mar 8 2015 Project Member

Issue description

The Type-2 CharString processing function (Type2BuildChar) implemented in the t2k font library as part of the Oracle Java Runtime Environment supports the "transient array" memory area, as specified in the "Type 2 Charstring format" specs [1]. While allocating the array, however, the routine does not clear the contents of the newly created buffer (which is a part of a larger structure storing the program state). If a reading PostScript instruction is then used to access an item in the array that has not been previously initialized, it is possible to leak data from the transient array into other structures and further use it e.g. as a parameter of the rendered font shapes. The possibility of such scenario is even mentioned in the [1] specification:

"If *get* is executed prior to *put* for /i/ during execution of the current charstring, the value returned is undefined."

As a result of the above JRE behavior, it is possible to read uninitialized memory via the "escape + get" PostScript instruction, which loads a 32-bit value from the transient array into the operand stack.

The bug is reproducible only with OTF fonts, because the "get" operator (and transient arrays in general) is not implemented in the Type-1 CharString processing function (Type1BuildChar). Therefore, the length of the transient array is always 32 elements, or 128 bytes (see the "Appendix B: Type 2 Charstring Implementation Limits" section of [1]).

The latest version of the t2k library at the time of this writing is confirmed to be affected (the one bundled with JRE 8u40), but we expect that all prior versions are prone to the bug, too. Attached is a Proof of Concept OTF font together with the source code of a Java class, which uses the enclosed font to render the glyph of letter 'a' in a window in an infinite loop. Since the font was designed so that the glyph shapes represent the leaked uninitialized memory, it is clearly visible that the problem exists, due to differences in how the glyph is displayed in respective runs.

More specifically, the font's letters 'a'-'z' are designed to disclose 128 bytes of process memory each by rendering each bit as a black 64x64 units square if the bit is set, or a white one if it is cleared. Therefore, each glyph is a 2048x2048 unit shape, with each of the 32 leaked DWORDs being represented as a separate column. The extraction of respective bits from a 32-bit value is not trivial with Type-2 CharString instructions, but is possible with the help of multiple arithmetic and conditional operations. The following is a Python function building a CharString payload to extract a specified bit off a specified leaked DWORD, used to create the attached POC font. Full source code of the script will be released at a later time.

While not all operators used in the POC font are supported by JRE, and thus the font does not render fully correctly in compliance with the specs, the seemingly non-deterministic nature of the rendered shapes still unquestionably show the flaw existence.

def leak_bit(dword, bit):
  # Leak a complete dword to the operand stack.
  payload = enc(dword) + cf2_cmdESC_GET

  # Because of signed arithmetic, we must handle the MSB separately.
  if bit == 31:
    payload += enc(0) + enc(1) + enc(0) + enc(3) + cf2_cmdESC_INDEX + cf2_cmdESC_IFELSE + cf2_cmdESC_EXCH + cf2_cmdESC_DROP
    # If the value is negative, flip the MSB for all further calculations.
    payload += enc(0) + enc_dword(2 ** 31) + enc(0) + enc(3) + cf2_cmdESC_INDEX + cf2_cmdESC_IFELSE + cf2_cmdESC_SUB

    # Subtract all bits more significant than the one we're leaking.
    for i in range(30, bit, -1):
      payload += enc(0) + enc_dword(2 ** i) + enc(2) + cf2_cmdESC_INDEX + enc_dword((2 ** i) - 1) + cf2_cmdESC_IFELSE + cf2_cmdESC_SUB

    # Return the specific bit by performing a 32-bit comparison.
    payload += enc(0) + enc(1) + enc(2) + cf2_cmdESC_INDEX + enc_dword((2 ** bit) - 1) + cf2_cmdESC_IFELSE + cf2_cmdESC_EXCH + cf2_cmdESC_DROP

  return payload

This bug is subject to a 90 day disclosure deadline. If 90 days elapse without a broadly available patch, then the bug report will automatically become visible to the public.

[1] "The Type 2 Charstring Format, Technical Note #5177, 16 March 2000",
1.5 MB Download

Comment 1 by, Apr 2 2015

Project Member
Labels: Reported-2015-Apr-2

Comment 2 by, Apr 10 2015

Project Member
Labels: Id-S0557014

Comment 3 by, Apr 20 2015

Project Member
Labels: Deadline-Exceeded Deadline-Grace
Grace period requested by Oracle. Fix expected Tue 14th July, or 13 days into grace period.

Comment 4 by, Jul 15 2015

Project Member
Labels: Fixed-2015-Jul-14
Status: Fixed
Fixed in

Comment 5 by, Jul 17 2015

Project Member
Labels: -Restrict-View-Commit

Comment 6 by, Jul 29 2015

Project Member
Labels: CVE-2015-2619

Sign in to add a comment