From 0f5ea9d269ac6225bcb302a1ec0f58878114da9f Mon Sep 17 00:00:00 2001 From: Olivier Fourdan Date: Mon, 16 Dec 2024 11:25:11 +0100 Subject: [PATCH xserver] Xi: Fix barrier device search The function GetBarrierDevice() would search for the pointer device based on its device id and return the matching value, or supposedly NULL if no match was found. Unfortunately, as written, it would return the last element of the list if no matching device id was found which can lead to out of bounds memory access. Fix the search function to return NULL if not matching device is found, and adjust the callers to handle the case where the device cannot be found. CVE-2025-26598, ZDI-CAN-25740 This vulnerability was discovered by: Jan-Niklas Sohn working with Trend Micro Zero Day Initiative Signed-off-by: Olivier Fourdan Reviewed-by: Peter Hutterer --- Xi/xibarriers.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) Index: xwayland-24.1.4/Xi/xibarriers.c =================================================================== --- xwayland-24.1.4.orig/Xi/xibarriers.c +++ xwayland-24.1.4/Xi/xibarriers.c @@ -129,14 +129,15 @@ static void FreePointerBarrierClient(str static struct PointerBarrierDevice *GetBarrierDevice(struct PointerBarrierClient *c, int deviceid) { - struct PointerBarrierDevice *pbd = NULL; + struct PointerBarrierDevice *p, *pbd = NULL; - xorg_list_for_each_entry(pbd, &c->per_device, entry) { - if (pbd->deviceid == deviceid) + xorg_list_for_each_entry(p, &c->per_device, entry) { + if (p->deviceid == deviceid) { + pbd = p; break; + } } - BUG_WARN(!pbd); return pbd; } @@ -337,6 +338,9 @@ barrier_find_nearest(BarrierScreenPtr cs double distance; pbd = GetBarrierDevice(c, dev->id); + if (!pbd) + continue; + if (pbd->seen) continue; @@ -445,6 +449,9 @@ input_constrain_cursor(DeviceIntPtr dev, nearest = &c->barrier; pbd = GetBarrierDevice(c, master->id); + if (!pbd) + continue; + new_sequence = !pbd->hit; pbd->seen = TRUE; @@ -485,6 +492,9 @@ input_constrain_cursor(DeviceIntPtr dev, int flags = 0; pbd = GetBarrierDevice(c, master->id); + if (!pbd) + continue; + pbd->seen = FALSE; if (!pbd->hit) continue; @@ -679,6 +689,9 @@ BarrierFreeBarrier(void *data, XID id) continue; pbd = GetBarrierDevice(c, dev->id); + if (!pbd) + continue; + if (!pbd->hit) continue; @@ -738,6 +751,8 @@ static void remove_master_func(void *res barrier = container_of(b, struct PointerBarrierClient, barrier); pbd = GetBarrierDevice(barrier, *deviceid); + if (!pbd) + return; if (pbd->hit) { BarrierEvent ev = { @@ -903,6 +918,10 @@ ProcXIBarrierReleasePointer(ClientPtr cl barrier = container_of(b, struct PointerBarrierClient, barrier); pbd = GetBarrierDevice(barrier, dev->id); + if (!pbd) { + client->errorValue = dev->id; + return BadDevice; + } if (pbd->barrier_event_id == event_id) pbd->release_event_id = event_id;