CLD-385 Details

Other IDs this deficiency may be known by:

CVE ID CVE-2017-9814 (nvd) (mitre) (debian) (archlinux) (red hat) (suse) (ubuntu)
Other ID(s)

Basic Information:

Affected Package(s) cairo
Deficiency Type SECURITY
Date Created 2018-05-09 21:09:32
Date Last Modified 2018-05-10 11:46:26

Version Specific Information:

Cucumber 1.0 i686fixed in cairo-1.14.8-i686-4
Cucumber 1.0 x86_64fixed in cairo-1.14.8-x86_64-4 and cairo-lib_i686-1.14.8-lib_i686-4

Cucumber 1.1 i686 fixed in cairo-1.14.8-i686-4
Cucumber 1.1 x86_64 fixed in cairo-1.14.8-x86_64-4 and cairo-lib_i686-1.14.8-lib_i686-4


=================================== Overview ===================================

cairo-truetype-subset.c in cairo 1.15.6 and earlier allows remote attackers to
cause a denial of service (out-of-bounds read) because of mishandling of an
unexpected malloc(0) call. 

================================ Initial Report ================================


The CVE-2017-9814 has been assigned to this vulnerability.

There is a read out of bounds bug at cairo-truetype-subset.c:1299:

1293     size = be16_to_cpu (map->length);
1294     map = malloc (size);
1295     if (unlikely (map == NULL))
1296         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1298     status = backend->load_truetype_table (scaled_font,
1299                                            TT_TAG_cmap, table_offset,
1300                                            (unsigned char *) map,
1301                                            &size);
1302     if (unlikely (status))
1303         goto fail;
1305     num_segments = be16_to_cpu (map->segCountX2)/2;

The bug happens because in some scenarios the variable size can have a value of
0 at line 1288. And malloc(0) is not returning NULL as some people could

malloc(0) returns the smallest chunk possible. So the line 1290 with the return
is not execute. And the execution continues with an invalid map.

Since the size is 0 the variable map is not initialized correctly at
load_trutype_table. So, later when the variable map is accessed previous values
from a freed chunk are used. This could allows an attacker to control the
variable map.

There is a check performed just after the bug:
1309     if (size < (8 + 4*num_segments)*sizeof(uint16_t))

So it's likely the attacker can't control the variable num_segments, and he
can't trigger additional functionality to leverage this.

The solution could be to check for the size, or to use a malloc wrapper that
handle the size = 0 case and returns NULL.

This bug was found when using a poppler util, pdftocairo. A PoC is attached. To
reproduce the bug use:
pdftocairo -svg PoC.pdf

This vulnerability has been found by Offensive Research at
Alberto Garcia (@algillera), Francisco Oca (@francisco_oca) & Suleman Ali

================================= Our Analysis =================================

----- Affected Products -----
It is reported that cairo up to and including 1.15.6 that have not been
speficially patched against this vulnerability are vulnerable. We have
confirmed that unpatched cairo 1.14.8 is vulnerable in our lab environment.
This includes cairo as orignally packaged with Cucumber Linux 1.0 and 1.1.

----- Scope and Impact of this Vulnerability -----
Could possibly allow for a denial of service (application crash). Note that we
have failed to produce a crash in our lab environment.

----- Testing if you are Affected -----
1.  Download PoC.pdf from
2.  Run the command `valgrind pdftocairo -svg PoC.pdf`.
    * Note: this will require you to install valgrind either from source or from
      the ports tree.

If the output of valgrind contains 'Invalid read of size 2', then you are

----- Fix for this Vulnerability -----
This vulnerability can be fixed by applying the patch from commit
We had to modify this patch to get it to work on Cucumber Linux 1.x. The
modified patch can be found at

This vulnerability has been fixed by adding an additional check to several
malloc()'s. Namely, malloc has been replaced with _cairo_malloc in severl
places, which checks and adiquately protects against a malloc(0) whereas the
former does not.

================================= Our Solution =================================

We have applied the patch from
and rebuilt.