untrusted comment: verify with openbsd-78-base.pub RWS3/nvFmk4SWdpYzWXOcNxeZdpXKU+SvhQIFxGcSKNMOkqpda4jQSMaTvtoMjnBCP5Myp/1SmmPXRcZgQ/pFbkJ3vs5D33sQQA= OpenBSD 7.8 errata 068, October 7, 2026: Multiple vulnerabilites in the X server Xinput, dix, glamor, glx, present and Xkb extensions. CVE-2026-88812 CVE-2026-93515 CVE-2026-93516 CVE-2026-93517 CVE-2026-93518 CVE-2026-93519 CVE-2026-93520 CVE-2026-93521 CVE-2026-93522 CVE-2026-93523 CVE-2026-93524 CVE-2026-93536 Apply by doing: signify -Vep /etc/signify/openbsd-78-base.pub -x 068_xserver.patch.sig \ -m - | (cd /usr/xenocara && patch -p0) And then rebuild and install the X server and keyboard drivers: cd /usr/xenocara/xserver make -f Makefile.bsd-wrapper obj make -f Makefile.bsd-wrapper build cd /usr/xenocara/driver/xf86-input-keyboard make -f Makefile.bsd-wrapper obj make -f Makefile.bsd-wrapper build Index: xserver/Xi/exevents.c =================================================================== RCS file: /cvs/xenocara/xserver/Xi/exevents.c,v diff -u -p -r1.30 exevents.c --- xserver/Xi/exevents.c 16 Jan 2024 12:34:23 -0000 1.30 +++ xserver/Xi/exevents.c 2 Oct 2026 09:35:04 -0000 @@ -2868,9 +2868,8 @@ InputClientGone(WindowPtr pWin, XID id) } /** - * Search for window in each touch trace for each device. Remove the window - * and all its subwindows from the trace when found. The initial window - * order is preserved. + * Search for window in each touch and gesture trace for each device. + * Truncate the trace when the window is found. */ void WindowGone(WindowPtr win) @@ -2881,11 +2880,22 @@ WindowGone(WindowPtr win) TouchClassPtr t = dev->touch; int i; - if (!t) - continue; + if (t) { + for (i = 0; i < t->num_touches; i++) { + SpritePtr sprite = &t->touches[i].sprite; + int j; - for (i = 0; i < t->num_touches; i++) { - SpritePtr sprite = &t->touches[i].sprite; + for (j = 0; j < sprite->spriteTraceGood; j++) { + if (sprite->spriteTrace[j] == win) { + sprite->spriteTraceGood = j; + break; + } + } + } + } + + if (dev->gesture) { + SpritePtr sprite = &dev->gesture->gesture.sprite; int j; for (j = 0; j < sprite->spriteTraceGood; j++) { Index: xserver/Xi/xibarriers.c =================================================================== RCS file: /cvs/xenocara/xserver/Xi/xibarriers.c,v diff -u -p -r1.7 xibarriers.c --- xserver/Xi/xibarriers.c 25 Feb 2025 15:52:12 -0000 1.7 +++ xserver/Xi/xibarriers.c 2 Oct 2026 09:35:04 -0000 @@ -416,6 +416,18 @@ input_constrain_cursor(DeviceIntPtr dev, InternalEvent *barrier_events = events; DeviceIntPtr master; + /* We cannot know how many events are available in *events, but + * we know it all DDX very protbably allocated them with + * GetMaximumEventsNum() and fill_pointer_events() may have added one. + * + * Let's cap at a maximum of 64 barrier events which is way more than + * we'll need but low enough that we shouldn't OOB on *events. + * + * Changing the signatures to get some sz_events in here is an ABI change + * through miPointerSetPosition so... weeping face. + */ + const int MAX_BARRIER_EVENTS = 64; + if (nevents) *nevents = 0; @@ -460,7 +472,6 @@ input_constrain_cursor(DeviceIntPtr dev, if (pbd->barrier_event_id == pbd->release_event_id) continue; - ev.type = ET_BarrierHit; barrier_clamp_to_barrier(nearest, dir, &x, &y); if (barrier_is_vertical(nearest)) { @@ -472,19 +483,22 @@ input_constrain_cursor(DeviceIntPtr dev, current_y = y; } - ev.flags = 0; - ev.event_id = pbd->barrier_event_id; - ev.barrierid = c->id; - - ev.dt = new_sequence ? 0 : ms - pbd->last_timestamp; - ev.window = c->window; + if (*nevents < MAX_BARRIER_EVENTS) { + ev.type = ET_BarrierHit; + ev.flags = 0; + ev.event_id = pbd->barrier_event_id; + ev.barrierid = c->id; + + ev.dt = new_sequence ? 0 : ms - pbd->last_timestamp; + ev.window = c->window; + + /* root x/y is filled in later */ + + barrier_events->barrier_event = ev; + barrier_events++; + *nevents += 1; + } pbd->last_timestamp = ms; - - /* root x/y is filled in later */ - - barrier_events->barrier_event = ev; - barrier_events++; - *nevents += 1; } xorg_list_for_each_entry(c, &cs->barriers, entry) { @@ -503,29 +517,31 @@ input_constrain_cursor(DeviceIntPtr dev, continue; pbd->hit = FALSE; + pbd->last_timestamp = ms; + /* If we've left the hit box, this is the + * start of a new event ID. */ + pbd->barrier_event_id++; - ev.type = ET_BarrierLeave; + if (*nevents < MAX_BARRIER_EVENTS) { + ev.type = ET_BarrierLeave; - if (pbd->barrier_event_id == pbd->release_event_id) - flags |= XIBarrierPointerReleased; + if (pbd->barrier_event_id == pbd->release_event_id) + flags |= XIBarrierPointerReleased; - ev.flags = flags; - ev.event_id = pbd->barrier_event_id; - ev.barrierid = c->id; + ev.flags = flags; + ev.event_id = pbd->barrier_event_id; + ev.barrierid = c->id; - ev.dt = ms - pbd->last_timestamp; - ev.window = c->window; - pbd->last_timestamp = ms; + ev.dt = ms - pbd->last_timestamp; + ev.window = c->window; - /* root x/y is filled in later */ + /* root x/y is filled in later */ - barrier_events->barrier_event = ev; - barrier_events++; - *nevents += 1; + barrier_events->barrier_event = ev; + barrier_events++; + *nevents += 1; + } - /* If we've left the hit box, this is the - * start of a new event ID. */ - pbd->barrier_event_id++; } out: @@ -557,8 +573,10 @@ CreatePointerBarrierClient(ClientPtr cli int size; int i; struct PointerBarrierClient *ret; + struct PointerBarrierClient *counter; CARD16 *in_devices; DeviceIntPtr dev; + size_t nbarriers = 0; size = sizeof(*ret) + sizeof(DeviceIntPtr) * stuff->num_devices; ret = malloc(size); @@ -577,6 +595,16 @@ CreatePointerBarrierClient(ClientPtr cli screen = pWin->drawable.pScreen; cs = GetBarrierScreen(screen); + + /* Only allow for a maximum of 32 barriers to be created. This + * should be more than enough and prevents issues in + * input_constrain_cursor, see MAX_BARRIER_EVENTS in that + * function */ + xorg_list_for_each_entry(counter, &cs->barriers, entry) { + nbarriers++; + if (nbarriers >= 32) + return BadAlloc; + } ret->screen = screen; ret->window = stuff->window; Index: xserver/Xi/xipassivegrab.c =================================================================== RCS file: /cvs/xenocara/xserver/Xi/xipassivegrab.c,v diff -u -p -r1.15 xipassivegrab.c --- xserver/Xi/xipassivegrab.c 7 Apr 2024 11:42:56 -0000 1.15 +++ xserver/Xi/xipassivegrab.c 2 Oct 2026 09:35:04 -0000 @@ -46,6 +46,10 @@ #include "misc.h" #include "inpututils.h" +#define AllModifiersMask ( \ + ShiftMask | LockMask | ControlMask | Mod1Mask | Mod2Mask | \ + Mod3Mask | Mod4Mask | Mod5Mask ) + int _X_COLD SProcXIPassiveGrabDevice(ClientPtr client) { @@ -346,6 +350,14 @@ ProcXIPassiveUngrabDevice(ClientPtr clie rc = dixLookupWindow(&win, stuff->grab_window, client, DixSetAttrAccess); if (rc != Success) return rc; + + modifiers = (uint32_t *) &stuff[1]; + for (i = 0; i < stuff->num_modifiers; i++, modifiers++) { + if (*modifiers != XIAnyModifier && (*modifiers & ~AllModifiersMask)) { + client->errorValue = *modifiers; + return BadValue; + } + } mod_dev = (IsFloating(dev)) ? dev : GetMaster(dev, MASTER_KEYBOARD); Index: xserver/dix/devices.c =================================================================== RCS file: /cvs/xenocara/xserver/dix/devices.c,v diff -u -p -r1.36 devices.c --- xserver/dix/devices.c 29 Jun 2025 05:21:57 -0000 1.36 +++ xserver/dix/devices.c 2 Oct 2026 09:35:04 -0000 @@ -1160,6 +1160,40 @@ UndisplayDevices(void) screen->DisplayCursor(dev, screen, NullCursor); } +static Bool +GrabReferencesDevice(void *value, XID id, void *cdata) +{ + GrabPtr grab = value; + DeviceIntPtr dev = cdata; + + return grab->device == dev || grab->modifierDevice == dev; +} + +/** + * Remove all passive grabs that reference the given device, either as + * the grabbed device or as the modifier device. This must be called + * before the device is freed to avoid dangling pointers in GrabRec. + */ +static void +RemovePassiveGrabsForDevice(DeviceIntPtr dev) +{ + int i; + + for (i = 0; i < currentMaxClients; i++) { + GrabPtr grab; + + if (!clients[i]) + continue; + + while ((grab = LookupClientResourceComplex(clients[i], + RT_PASSIVEGRAB, + GrabReferencesDevice, + dev))) { + FreeResource(grab->resource, RT_NONE); + } + } +} + /** * Remove a device from the device list, closes it and thus frees all * resources. @@ -1198,6 +1232,8 @@ RemoveDevice(DeviceIntPtr dev, BOOL send DisableDevice(dev, sendevent); flags[dev->id] = XIDeviceDisabled; } + + RemovePassiveGrabsForDevice(dev); input_lock(); Index: xserver/glamor/glamor_priv.h =================================================================== RCS file: /cvs/xenocara/xserver/glamor/glamor_priv.h,v diff -u -p -r1.9 glamor_priv.h --- xserver/glamor/glamor_priv.h 11 Nov 2021 09:03:03 -0000 1.9 +++ xserver/glamor/glamor_priv.h 2 Oct 2026 09:35:04 -0000 @@ -511,6 +511,30 @@ glamor_pixmap_hcnt(glamor_pixmap_private for (box_index = 0; box_index < glamor_pixmap_hcnt(priv) * \ glamor_pixmap_wcnt(priv); box_index++) \ +static inline int +glamor_drawable_effective_depth(DrawablePtr drawable) +{ + WindowPtr window; + + if (drawable->type != DRAWABLE_WINDOW || + drawable->depth != 32) + return drawable->depth; + + window = (WindowPtr)drawable; + window = window->parent; + while (window && window->parent) { + /* A depth 32 window with any depth 24 ancestors (other than the root + * window) effectively behaves like depth 24 + */ + if (window->drawable.depth == 24) + return 24; + + window = window->parent; + } + + return 32; +} + /* GC private structure. Currently holds only any computed dash pixmap */ typedef struct { Index: xserver/glamor/glamor_transfer.c =================================================================== RCS file: /cvs/xenocara/xserver/glamor/glamor_transfer.c,v diff -u -p -r1.6 glamor_transfer.c --- xserver/glamor/glamor_transfer.c 11 Nov 2021 09:03:03 -0000 1.6 +++ xserver/glamor/glamor_transfer.c 2 Oct 2026 09:35:04 -0000 @@ -38,6 +38,16 @@ glamor_upload_boxes(PixmapPtr pixmap, Bo int box_index; int bytes_per_pixel = pixmap->drawable.bitsPerPixel >> 3; const struct glamor_format *f = glamor_format_for_pixmap(pixmap); + char *tmp_bits = NULL; + + if (glamor_drawable_effective_depth(&pixmap->drawable) == 24 && pixmap->drawable.depth == 32) { + int tmp_height = pixmap->drawable.height - dy_dst + dy_src; + if (tmp_height > 0) { + if (byte_stride > 0 && tmp_height > INT_MAX / byte_stride) + return; + tmp_bits = XNFalloc(byte_stride * tmp_height); + } + } glamor_make_current(glamor_priv); Index: xserver/glx/glxcmds.c =================================================================== RCS file: /cvs/xenocara/xserver/glx/glxcmds.c,v diff -u -p -r1.21.8.1 glxcmds.c --- xserver/glx/glxcmds.c 2 Jun 2026 06:01:57 -0000 1.21.8.1 +++ xserver/glx/glxcmds.c 2 Oct 2026 09:35:04 -0000 @@ -2190,6 +2190,9 @@ __glXDisp_RenderLarge(__GLXclientState * return BadLength; } + if (dataBytes > cmdlen) + return BadLength; + /* ** Make enough space in the buffer, then copy the entire request. */ Index: xserver/include/xkbstr.h =================================================================== RCS file: /cvs/xenocara/xserver/include/xkbstr.h,v diff -u -p -r1.6 xkbstr.h --- xserver/include/xkbstr.h 11 Nov 2021 09:03:13 -0000 1.6 +++ xserver/include/xkbstr.h 2 Oct 2026 09:35:05 -0000 @@ -311,8 +311,8 @@ typedef struct _XkbControls { XkbAX_NeedOption((c), (w))) typedef struct _XkbServerMapRec { - unsigned short num_acts; - unsigned short size_acts; + unsigned int num_acts; + unsigned int size_acts; XkbAction *acts; XkbBehavior *behaviors; @@ -345,8 +345,8 @@ typedef struct _XkbClientMapRec { unsigned char num_types; XkbKeyTypePtr types; - unsigned short size_syms; - unsigned short num_syms; + unsigned int size_syms; + unsigned int num_syms; KeySym *syms; XkbSymMapPtr key_sym_map; Index: xserver/present/present_notify.c =================================================================== RCS file: /cvs/xenocara/xserver/present/present_notify.c,v diff -u -p -r1.2.16.1 present_notify.c --- xserver/present/present_notify.c 28 Oct 2025 13:26:59 -0000 1.2.16.1 +++ xserver/present/present_notify.c 2 Oct 2026 09:35:05 -0000 @@ -30,14 +30,14 @@ void present_clear_window_notifies(WindowPtr window) { - present_notify_ptr notify; + present_notify_ptr notify, tmp; present_window_priv_ptr window_priv = present_window_priv(window); if (!window_priv) return; - xorg_list_for_each_entry(notify, &window_priv->notifies, window_list) { - notify->window = NULL; + xorg_list_for_each_entry_safe(notify, tmp, &window_priv->notifies, window_list) { + present_free_window_notify(notify); } } @@ -48,6 +48,7 @@ present_clear_window_notifies(WindowPtr void present_free_window_notify(present_notify_ptr notify) { + notify->window = NULL; xorg_list_del(¬ify->window_list); } Index: xserver/xkb/XKBAlloc.c =================================================================== RCS file: /cvs/xenocara/xserver/xkb/XKBAlloc.c,v diff -u -p -r1.9 XKBAlloc.c --- xserver/xkb/XKBAlloc.c 29 Jun 2025 05:21:57 -0000 1.9 +++ xserver/xkb/XKBAlloc.c 2 Oct 2026 09:35:05 -0000 @@ -148,7 +148,7 @@ XkbAllocNames(XkbDescPtr xkb, unsigned w (!XkbIsLegalKeycode(xkb->max_key_code)) || (xkb->max_key_code < xkb->min_key_code)) return BadValue; - names->keys = calloc((xkb->max_key_code + 1), sizeof(XkbKeyNameRec)); + names->keys = calloc(MAP_LENGTH, sizeof(XkbKeyNameRec)); if (names->keys == NULL) return BadAlloc; } Index: xserver/xkb/XKBMAlloc.c =================================================================== RCS file: /cvs/xenocara/xserver/xkb/XKBMAlloc.c,v diff -u -p -r1.12 XKBMAlloc.c --- xserver/xkb/XKBMAlloc.c 29 Jun 2025 05:21:57 -0000 1.12 +++ xserver/xkb/XKBMAlloc.c 2 Oct 2026 09:35:05 -0000 @@ -386,7 +386,8 @@ XkbResizeKeyType(XkbDescPtr xkb, } if (nResize > 0) { int nextMatch; - + if (nTotal > INT_MAX / 15) + return BadAlloc; xkb->map->size_syms = (nTotal * 15) / 10; newSyms = calloc(xkb->map->size_syms, sizeof(KeySym)); if (newSyms == NULL) Index: xserver/xkb/xkb.c =================================================================== RCS file: /cvs/xenocara/xserver/xkb/xkb.c,v diff -u -p -r1.26.4.3 xkb.c --- xserver/xkb/xkb.c 2 Jun 2026 06:01:58 -0000 1.26.4.3 +++ xserver/xkb/xkb.c 2 Oct 2026 09:35:05 -0000 @@ -1809,6 +1809,7 @@ CheckKeySyms(ClientPtr client, wire = (xkbSymMapWireDesc *) &pSyms[wire->nSyms]; } + i = req->firstKeySym + req->nKeySyms; map = &xkb->map->key_sym_map[i]; for (; i <= (unsigned) xkb->max_key_code; i++, map++) { register int g, nG, w; @@ -5294,7 +5295,8 @@ _CheckSetDoodad(char **wire_inout, xkbSe return status; status = _GetCountedString(&wire, client, &doodad->text.font); if (status != Success) { - free (doodad->text.text); + free(doodad->text.text); + doodad->text.text = NULL; return status; } break;