Manipulation with global linked list from multiple threads not protected by mutex
In CairoFontEngine.cc
exists global linked list which is manipulated by _ft_new_face
and _ft_done_face
#ifdef CAN_CHECK_OPEN_FACES
static struct _ft_face_data {
struct _ft_face_data *prev, *next, **head;
int fd;
unsigned long hash;
size_t size;
unsigned char *bytes;
FT_Library lib;
FT_Face face;
cairo_font_face_t *font_face;
} *_ft_open_faces;
for (l = _ft_open_faces; l; l = l->next) {
if (_ft_face_data_equal (l, &tmpl)) {
if (tmpl.fd != -1) {
#if defined(__SUNPRO_CC) && defined(__sun) && defined(__SVR4)
munmap ((char*)tmpl.bytes, tmpl.size);
#else
munmap (tmpl.bytes, tmpl.size);
#endif
close (tmpl.fd);
} else {
gfree (tmpl.bytes);
}
*face_out = l->face;
*font_face_out = cairo_font_face_reference (l->font_face);
return gTrue;
}
}
Attached test_mt_sigsegv.zip
Output from GDB:
Thread 4 "a.out" received signal SIGSEGV, Segmentation fault.
INT_cairo_font_face_reference (font_face=0x3200000008) at ../../../../src/cairo-font-face.c:125
125 ../../../../src/cairo-font-face.c: No such file or directory.
#0 0x00007ffff756f7e8 in INT_cairo_font_face_reference (font_face=0x3200000008) at ../../../../src/cairo-font-face.c:125
#1 0x00007ffff7baf621 in _ft_new_face(FT_Library, char const*, char*, int, FT_Face*, cairo_font_face_t**) (lib=lib@entry=0x7fffc0001600, filename=filename@entry=0x0, font_data=font_data@entry=0x7fffe4064e50 "true", font_data_len=<optimized out>, face_out=face_out@entry=0x7fffefadb490, font_face_out=font_face_out@entry=0x7fffefadb498) at ./poppler/CairoFontEngine.cc:331
#2 0x00007ffff7bafd5a in CairoFreeTypeFont::create(GfxFont*, XRef*, FT_LibraryRec_*, bool) (gfxFont=gfxFont@entry=0x7fffe403a370, xref=xref@entry=0x7fffe4034db0, lib=0x7fffc0001600, useCIDs=<optimized out>) at ./poppler/CairoFontEngine.cc:524
#3 0x00007ffff7bb05c8 in CairoFontEngine::getFont(GfxFont*, PDFDoc*, bool, XRef*) (this=0x7fffe4037040, gfxFont=0x7fffe403a370, doc=0x7fffe4001350, printing=false, xref=0x7fffe4034db0) at ./poppler/CairoFontEngine.cc:862
#4 0x00007ffff7bb117f in CairoOutputDev::updateFont(GfxState*) (this=0x7fffe4036df0, state=0x7fffe4052880) at ./poppler/CairoOutputDev.cc:668
#5 0x00007ffff6615252 in Gfx::opShowSpaceText(Object*, int) () at /usr/lib/x86_64-linux-gnu/libpoppler.so.73
I am getting this almost always instantly after run. Tested with poppler 0.62.0 on ubuntu 18.04 (and poppler 0.48.0 on debian stretch) on cpu with 12/24 cores. On other systems it may need more time. It can sometimes also end up with abort signal.
Where font_face
argument to cairo_font_face_reference
is arbitrary value which happened to be on stack because it can end up initialised only after is new entry added into linked list:
l = (struct _ft_face_data *) gmallocn (1, sizeof (struct _ft_face_data));
*l = tmpl;
l->prev = NULL;
l->next = _ft_open_faces;
if (_ft_open_faces)
_ft_open_faces->prev = l;
_ft_open_faces = l;
l->font_face = cairo_ft_font_face_create_for_ft_face (tmpl.face,
This is potentially security vulnerability for applications which use poppler and cairo to render in multiple threads.
tmpl = {..., font_face = 0x3200000008}
It would be no more better to reorder this in source code because compiler can reorder back. There is needed synchronisation mechanism like mutex.
The best would be to remove this global caching which is controlled by CAN_CHECK_OPEN_FACES. It would partially resolve also #845 (closed).