diff options
author | Michel Dänzer <michel.daenzer@amd.com> | 2017-02-16 16:13:56 +0900 |
---|---|---|
committer | Adam Jackson <ajax@redhat.com> | 2017-02-16 14:14:11 -0500 |
commit | a6566f9e4dbf9ea9568a14e22cb5d004e10dbd4d (patch) | |
tree | ab972ea077b6bda3a70e0b301ed9b1686770e06b /dix | |
parent | 371ff0c969a38a0013688391bbd7375bc7b6f933 (diff) |
prime: Clear PixmapDirtyUpdateRec::damage when it's destroyed
The root window, and by extension any damage records referencing it,
may be destroyed before shared pixmaps referencing it, which resulted in
use-after-free / double-free in PixmapStopDirtyTracking.
Fixes: b5b292896f64 ("prime: Sync shared pixmap from root window instead of screen pixmap")
Reviewed-by: Adam Jackson <ajax@redhat.com>
Signed-off-by: Michel Dänzer <michel.daenzer@amd.com>
Diffstat (limited to 'dix')
-rw-r--r-- | dix/pixmap.c | 15 |
1 files changed, 12 insertions, 3 deletions
diff --git a/dix/pixmap.c b/dix/pixmap.c index ef0083083..b67a2e8a6 100644 --- a/dix/pixmap.c +++ b/dix/pixmap.c @@ -172,6 +172,14 @@ PixmapPtr PixmapShareToSlave(PixmapPtr pixmap, ScreenPtr slave) return spix; } +static void +PixmapDirtyDamageDestroy(DamagePtr damage, void *closure) +{ + PixmapDirtyUpdatePtr dirty = closure; + + dirty->damage = NULL; +} + Bool PixmapStartDirtyTracking(PixmapPtr src, PixmapPtr slave_dst, @@ -195,10 +203,10 @@ PixmapStartDirtyTracking(PixmapPtr src, dirty_update->dst_x = dst_x; dirty_update->dst_y = dst_y; dirty_update->rotation = rotation; - dirty_update->damage = DamageCreate(NULL, NULL, + dirty_update->damage = DamageCreate(NULL, PixmapDirtyDamageDestroy, DamageReportNone, TRUE, src->drawable.pScreen, - src->drawable.pScreen); + dirty_update); if (rotation != RR_Rotate_0) { RRTransformCompute(x, y, @@ -247,7 +255,8 @@ PixmapStopDirtyTracking(PixmapPtr src, PixmapPtr slave_dst) xorg_list_for_each_entry_safe(ent, safe, &screen->pixmap_dirty_list, ent) { if (ent->src == src && ent->slave_dst == slave_dst) { - DamageDestroy(ent->damage); + if (ent->damage) + DamageDestroy(ent->damage); xorg_list_del(&ent->ent); free(ent); } |