summaryrefslogtreecommitdiff
path: root/render
diff options
context:
space:
mode:
authorPeter Hutterer <peter.hutterer@who-t.net>2024-01-30 13:13:35 +1000
committerAlan Coopersmith <alan.coopersmith@oracle.com>2024-04-02 19:19:40 -0700
commitbdca6c3d1f5057eeb31609b1280fc93237b00c77 (patch)
tree02f045218d48efd57f00c37216565b41af15b0e1 /render
parent6c684d035c06fd41c727f0ef0744517580864cef (diff)
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>
Diffstat (limited to 'render')
-rw-r--r--render/glyph.c5
-rw-r--r--render/glyphstr_priv.h1
-rw-r--r--render/render.c15
3 files changed, 15 insertions, 6 deletions
diff --git a/render/glyph.c b/render/glyph.c
index 850ea8440..13991f8a1 100644
--- a/render/glyph.c
+++ b/render/glyph.c
@@ -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);
diff --git a/render/glyphstr_priv.h b/render/glyphstr_priv.h
index 90a90fa4f..dd1bc5482 100644
--- a/render/glyphstr_priv.h
+++ b/render/glyphstr_priv.h
@@ -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);
diff --git a/render/render.c b/render/render.c
index 29c5055c6..fe5e37dd9 100644
--- a/render/render.c
+++ b/render/render.c
@@ -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)
- free(glyphs[i].glyph);
+ 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;