Pdfium - Out-of-Bounds Read with Shading Pattern Backed by Pattern Colorspace









Related to  issue 1490 .

When parsing ShadingPatterns; according to the specification they shouldn't be permitted to have a pattern colorspace as their base colorspace, but this is not validated, leading to out-of-bounds reads when rendering using the malformed shading pattern.

bool CPDF_ShadingPattern::Load() {

  // ... snip ...

  CPDF_Object* pCSObj = pShadingDict->GetDirectObjectFor("ColorSpace");
  if (!pCSObj)
    return false;

  // No validation here on the type of colorspace.

  // ... snip ...

  return true;

If we now look at the code called during rendering of this pattern, we call through DrawFreeGouraudShading (cpdf_renderstatus.cpp), which will call CPDF_MeshStream::ReadVertex for each vertex in the shading pattern, which will call CPDF_MeshStream::ReadColor.

std::tuple<float, float, float> CPDF_MeshStream::ReadColor() {

  float color_value[kMaxComponents];
  for (uint32_t i = 0; i < m_nComponents; ++i) {
    color_value[i] = m_ColorMin[i] + m_BitStream->GetBits(m_nComponentBits) *
                                         (m_ColorMax[i] - m_ColorMin[i]) /

  // NB: color_value has only been initialised for the first m_nComponents elements

  float r = 0.0;
  float g = 0.0;
  float b = 0.0;
  if (m_funcs.empty()) {
    m_pCS->GetRGB(color_value, &r, &g, &b); // <-- we're interested in this call here
    return std::tuple<float, float, float>(r, g, b);

  // ... snip ...

This call to GetRGB will be into the pattern cs

bool CPDF_PatternCS::GetRGB(float* pBuf, float* R, float* G, float* B) const {
  if (m_pBaseCS) {
    ASSERT(m_pBaseCS->GetFamily() != PDFCS_PATTERN);
    PatternValue* pvalue = (PatternValue*)pBuf;
    // pvalue->m_Comps is now pointing 5 dwords into an 8 dword sized buffer, and p_pBaseCS expects to be able to read 8 dwords from it. 
    if (m_pBaseCS->GetRGB(pvalue->m_Comps, R, G, B))
      return true;
  *R = 0.75f;
  *G = 0.75f;
  *B = 0.75f;
  return false;

Originally reported without 90 day deadline as https://bugs.chromium.org/p/chromium/issues/detail?id=795251, since it wasn't clear that there was an easy way to use the oob-read to leak information in a way that was useful, deadline applied as of 15/12 after working out how to use this as an information leak for  issue 1489 . 

Proof of Concept: