render: fix refcounting of glyphs during ProcRenderAddGlyphs
Previously, AllocateGlyph would return a new glyph with refcount=0 and a re-used glyph would end up not changing the refcount at all. The resulting glyph_new array would thus have multiple entries pointing to the same non-refcounted glyphs. AddGlyph may free a glyph, resulting in a UAF when the same glyph pointer is then later used. Fix this by returning a refcount of 1 for a new glyph and always incrementing the refcount for a re-used glyph, followed by dropping that refcount back down again when we're done with it. CVE-2024-31083, ZDI-CAN-22880 This vulnerability was discovered by: Jan-Niklas Sohn working with Trend Micro Zero Day Initiative Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1463>
This commit is contained in:
parent
6c684d035c
commit
bdca6c3d1f
|
@ -245,10 +245,11 @@ FreeGlyphPicture(GlyphPtr glyph)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
FreeGlyph(GlyphPtr glyph, int format)
|
||||
{
|
||||
CheckDuplicates(&globalGlyphs[format], "FreeGlyph");
|
||||
BUG_RETURN(glyph->refcnt == 0);
|
||||
if (--glyph->refcnt == 0) {
|
||||
GlyphRefPtr gr;
|
||||
int i;
|
||||
|
@ -354,7 +355,7 @@ AllocateGlyph(xGlyphInfo * gi, int fdepth)
|
|||
glyph = (GlyphPtr) malloc(size);
|
||||
if (!glyph)
|
||||
return 0;
|
||||
glyph->refcnt = 0;
|
||||
glyph->refcnt = 1;
|
||||
glyph->size = size + sizeof(xGlyphInfo);
|
||||
glyph->info = *gi;
|
||||
dixInitPrivates(glyph, (char *) glyph + head_size, PRIVATE_GLYPH);
|
||||
|
|
|
@ -56,6 +56,7 @@ void AddGlyph(GlyphSetPtr glyphSet, GlyphPtr glyph, Glyph id);
|
|||
Bool DeleteGlyph(GlyphSetPtr glyphSet, Glyph id);
|
||||
GlyphPtr FindGlyph(GlyphSetPtr glyphSet, Glyph id);
|
||||
GlyphPtr AllocateGlyph(xGlyphInfo * gi, int format);
|
||||
void FreeGlyph(GlyphPtr glyph, int format);
|
||||
Bool ResizeGlyphSet(GlyphSetPtr glyphSet, CARD32 change);
|
||||
GlyphSetPtr AllocateGlyphSet(int fdepth, PictFormatPtr format);
|
||||
int FreeGlyphSet(void *value, XID gid);
|
||||
|
|
|
@ -1076,6 +1076,7 @@ ProcRenderAddGlyphs(ClientPtr client)
|
|||
|
||||
if (glyph_new->glyph && glyph_new->glyph != DeletedGlyph) {
|
||||
glyph_new->found = TRUE;
|
||||
++glyph_new->glyph->refcnt;
|
||||
}
|
||||
else {
|
||||
GlyphPtr glyph;
|
||||
|
@ -1168,8 +1169,10 @@ ProcRenderAddGlyphs(ClientPtr client)
|
|||
err = BadAlloc;
|
||||
goto bail;
|
||||
}
|
||||
for (i = 0; i < nglyphs; i++)
|
||||
for (i = 0; i < nglyphs; i++) {
|
||||
AddGlyph(glyphSet, glyphs[i].glyph, glyphs[i].id);
|
||||
FreeGlyph(glyphs[i].glyph, glyphSet->fdepth);
|
||||
}
|
||||
|
||||
if (glyphsBase != glyphsLocal)
|
||||
free(glyphsBase);
|
||||
|
@ -1179,9 +1182,13 @@ ProcRenderAddGlyphs(ClientPtr client)
|
|||
FreePicture((void *) pSrc, 0);
|
||||
if (pSrcPix)
|
||||
FreeScratchPixmapHeader(pSrcPix);
|
||||
for (i = 0; i < nglyphs; i++)
|
||||
if (glyphs[i].glyph && !glyphs[i].found)
|
||||
for (i = 0; i < nglyphs; i++) {
|
||||
if (glyphs[i].glyph) {
|
||||
--glyphs[i].glyph->refcnt;
|
||||
if (!glyphs[i].found)
|
||||
free(glyphs[i].glyph);
|
||||
}
|
||||
}
|
||||
if (glyphsBase != glyphsLocal)
|
||||
free(glyphsBase);
|
||||
return err;
|
||||
|
|
Loading…
Reference in New Issue