已合并
fix CVE-2026-50256 CVE-2026-50257 CVE-2026-50258 CVE-2026-50259 CVE-2026-50260 CVE-2026-50261 CVE-2026-50262 CVE-2026-50263 CVE-2026-50264 #402
ultra_planet创建于 6月8日
fix CVE-2026-50256 CVE-2026-50257 CVE-2026-50258 CVE-2026-50259 CVE-2026-50260 CVE-2026-50261 CVE-2026-50262 CVE-2026-50263 CVE-2026-50264 #402
已合并
共 10 个文件变更+901-1
| @@ -0,0 +1,112 @@ | |||
| 1 | +From 4926348d826b7dc12d51d7e41bd9068aee5f90af Mon Sep 17 00:00:00 2001 | ||
| 2 | +From: =?UTF-8?q?Michel=20D=C3=A4nzer?= <mdaenzer@redhat.com> | ||
| 3 | +Date: Wed, 13 May 2026 14:29:26 +0200 | ||
| 4 | +Subject: [PATCH] dri2: Use booleans for (fake) front buffer tracking in | ||
| 5 | + do_get_buffers | ||
| 6 | +MIME-Version: 1.0 | ||
| 7 | +Content-Type: text/plain; charset=UTF-8 | ||
| 8 | +Content-Transfer-Encoding: 8bit | ||
| 9 | + | ||
| 10 | +This works as intended — the (fake) front buffer needs to be added | ||
| 11 | +only if the client didn't request it in the first place — even if the | ||
| 12 | +client requests the same attachment multiple times. This ensures we | ||
| 13 | +never try to access more than (count + 1) entries of the buffers array. | ||
| 14 | + | ||
| 15 | +Fixes: ff6c7764c290 ("DRI2: Implement protocol for DRI2GetBuffersWithFormat") | ||
| 16 | +Signed-off-by: Michel Dänzer <mdaenzer@redhat.com> | ||
| 17 | +(cherry picked from commit b7aa65cc3bb11b792ce2a3f511ba9b863acb11c8) | ||
| 18 | + | ||
| 19 | +Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2229> | ||
| 20 | + | ||
| 21 | +Reference:https://gitlab.freedesktop.org/xorg/xserver/-/commit/4926348d826b7dc12d51d7e41bd9068aee5f90af | ||
| 22 | +Conflict:no | ||
| 23 | +--- | ||
| 24 | + hw/xfree86/dri2/dri2.c | 37 ++++++++++++++++++------------------- | ||
| 25 | + 1 file changed, 18 insertions(+), 19 deletions(-) | ||
| 26 | + | ||
| 27 | +diff --git a/hw/xfree86/dri2/dri2.c b/hw/xfree86/dri2/dri2.c | ||
| 28 | +index 3975d40ca..5c251cc5a 100644 | ||
| 29 | +--- a/hw/xfree86/dri2/dri2.c | ||
| 30 | ++++ b/hw/xfree86/dri2/dri2.c | ||
| 31 | + do_get_buffers(DrawablePtr pDraw, int *width, int *height, | ||
| 32 | + DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw); | ||
| 33 | + DRI2ScreenPtr ds; | ||
| 34 | + DRI2BufferPtr *buffers; | ||
| 35 | +- int need_real_front = 0; | ||
| 36 | +- int need_fake_front = 0; | ||
| 37 | +- int have_fake_front = 0; | ||
| 38 | ++ Bool need_real_front = FALSE; | ||
| 39 | ++ Bool have_real_front = FALSE; | ||
| 40 | ++ Bool need_fake_front = FALSE; | ||
| 41 | ++ Bool have_fake_front = FALSE; | ||
| 42 | + int front_format = 0; | ||
| 43 | + int dimensions_match; | ||
| 44 | + int buffers_changed = 0; | ||
| 45 | + do_get_buffers(DrawablePtr pDraw, int *width, int *height, | ||
| 46 | + if (buffers[i] == NULL) | ||
| 47 | + goto err_out; | ||
| 48 | + | ||
| 49 | +- /* If the drawable is a window and the front-buffer is requested, | ||
| 50 | +- * silently add the fake front-buffer to the list of requested | ||
| 51 | +- * attachments. The counting logic in the loop accounts for the case | ||
| 52 | +- * where the client requests both the fake and real front-buffer. | ||
| 53 | ++ /* In certain cases the (fake) front buffer is always needed, so return | ||
| 54 | ++ * it even if the client failed to request it. | ||
| 55 | ++ * The logic in & after the loop accounts for the case where the client | ||
| 56 | ++ * does request the (fake) front buffer, to avoid returning it multiple | ||
| 57 | ++ * times. | ||
| 58 | + */ | ||
| 59 | + if (attachment == DRI2BufferBackLeft) { | ||
| 60 | +- need_real_front++; | ||
| 61 | ++ need_real_front = TRUE; | ||
| 62 | + front_format = format; | ||
| 63 | + } | ||
| 64 | + | ||
| 65 | + if (attachment == DRI2BufferFrontLeft) { | ||
| 66 | +- need_real_front--; | ||
| 67 | ++ have_real_front = TRUE; | ||
| 68 | + front_format = format; | ||
| 69 | + | ||
| 70 | +- if (pDraw->type == DRAWABLE_WINDOW) { | ||
| 71 | +- need_fake_front++; | ||
| 72 | +- } | ||
| 73 | ++ if (pDraw->type == DRAWABLE_WINDOW) | ||
| 74 | ++ need_fake_front = TRUE; | ||
| 75 | + } | ||
| 76 | + | ||
| 77 | + if (pDraw->type == DRAWABLE_WINDOW) { | ||
| 78 | +- if (attachment == DRI2BufferFakeFrontLeft) { | ||
| 79 | +- need_fake_front--; | ||
| 80 | +- have_fake_front = 1; | ||
| 81 | +- } | ||
| 82 | ++ if (attachment == DRI2BufferFakeFrontLeft) | ||
| 83 | ++ have_fake_front = TRUE; | ||
| 84 | + } | ||
| 85 | + } | ||
| 86 | + | ||
| 87 | +- if (need_real_front > 0) { | ||
| 88 | ++ if (need_real_front && !have_real_front) { | ||
| 89 | + if (allocate_or_reuse_buffer(pDraw, ds, pPriv, DRI2BufferFrontLeft, | ||
| 90 | + front_format, dimensions_match, | ||
| 91 | + &buffers[i])) | ||
| 92 | + do_get_buffers(DrawablePtr pDraw, int *width, int *height, | ||
| 93 | + i++; | ||
| 94 | + } | ||
| 95 | + | ||
| 96 | +- if (need_fake_front > 0) { | ||
| 97 | ++ if (need_fake_front && !have_fake_front) { | ||
| 98 | + if (allocate_or_reuse_buffer(pDraw, ds, pPriv, DRI2BufferFakeFrontLeft, | ||
| 99 | + front_format, dimensions_match, | ||
| 100 | + &buffers[i])) | ||
| 101 | + do_get_buffers(DrawablePtr pDraw, int *width, int *height, | ||
| 102 | + goto err_out; | ||
| 103 | + | ||
| 104 | + i++; | ||
| 105 | +- have_fake_front = 1; | ||
| 106 | ++ have_fake_front = TRUE; | ||
| 107 | + } | ||
| 108 | + | ||
| 109 | + *out_count = i; | ||
| 110 | +-- | ||
| 111 | +2.33.0 | ||
| 112 | + | ||
| @@ -0,0 +1,143 @@ | |||
| 1 | +From f0b8e6e1d969548c0625051d56a780e5df39de26 Mon Sep 17 00:00:00 2001 | ||
| 2 | +From: =?UTF-8?q?Michel=20D=C3=A4nzer?= <mdaenzer@redhat.com> | ||
| 3 | +Date: Fri, 15 May 2026 17:47:51 +0200 | ||
| 4 | +Subject: [PATCH] dri2: Deduplicate attachments in do_get_buffer | ||
| 5 | +MIME-Version: 1.0 | ||
| 6 | +Content-Type: text/plain; charset=UTF-8 | ||
| 7 | +Content-Transfer-Encoding: 8bit | ||
| 8 | + | ||
| 9 | +It was always the intention of the DRI2 protocol that there's at most | ||
| 10 | +one instance of each attachment, and that's how it was implemented in | ||
| 11 | +Mesa. | ||
| 12 | + | ||
| 13 | +Since that wasn't enforced though, there might be other clients in the | ||
| 14 | +wild which (e.g. accidentally) request the same attachment multiple | ||
| 15 | +times. So starting to a raise a protocol error in this case now risks | ||
| 16 | +breaking such clients. | ||
| 17 | + | ||
| 18 | +Instead, just deduplicate the attachments using a bit-set. | ||
| 19 | + | ||
| 20 | +This has a couple of desirable side effects: | ||
| 21 | + | ||
| 22 | +* destroy_buffer cannot be called multiple times for the same | ||
| 23 | + DRI2BufferPtr. | ||
| 24 | +* The client cannot cause the server to allocate a buffers array with | ||
| 25 | + more entries than there are attachments (currently 11). | ||
| 26 | + | ||
| 27 | +Signed-off-by: Michel Dänzer <mdaenzer@redhat.com> | ||
| 28 | +(cherry picked from commit 339c279514326134b0878fc23ce6e9520440ce7f) | ||
| 29 | + | ||
| 30 | +Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2229> | ||
| 31 | + | ||
| 32 | +Reference:https://gitlab.freedesktop.org/xorg/xserver/-/commit/f0b8e6e1d969548c0625051d56a780e5df39de26 | ||
| 33 | +Conflict:no | ||
| 34 | +--- | ||
| 35 | + hw/xfree86/dri2/dri2.c | 36 ++++++++++++++++++++++-------------- | ||
| 36 | + 1 file changed, 22 insertions(+), 14 deletions(-) | ||
| 37 | + | ||
| 38 | +diff --git a/hw/xfree86/dri2/dri2.c b/hw/xfree86/dri2/dri2.c | ||
| 39 | +index 5c251cc5a..bf62538c5 100644 | ||
| 40 | +--- a/hw/xfree86/dri2/dri2.c | ||
| 41 | ++++ b/hw/xfree86/dri2/dri2.c | ||
| 42 | + do_get_buffers(DrawablePtr pDraw, int *width, int *height, | ||
| 43 | + DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw); | ||
| 44 | + DRI2ScreenPtr ds; | ||
| 45 | + DRI2BufferPtr *buffers; | ||
| 46 | ++ unsigned attachments_bitset = 0; | ||
| 47 | + Bool need_real_front = FALSE; | ||
| 48 | +- Bool have_real_front = FALSE; | ||
| 49 | + Bool need_fake_front = FALSE; | ||
| 50 | +- Bool have_fake_front = FALSE; | ||
| 51 | + int front_format = 0; | ||
| 52 | + int dimensions_match; | ||
| 53 | + int buffers_changed = 0; | ||
| 54 | + int i; | ||
| 55 | + | ||
| 56 | +- if (!pPriv) { | ||
| 57 | ++ if (!pPriv || | ||
| 58 | ++ count > DRI2BufferHiz + 1) { | ||
| 59 | + *width = pDraw->width; | ||
| 60 | + *height = pDraw->height; | ||
| 61 | + *out_count = 0; | ||
| 62 | + do_get_buffers(DrawablePtr pDraw, int *width, int *height, | ||
| 63 | + dimensions_match = (pDraw->width == pPriv->width) | ||
| 64 | + && (pDraw->height == pPriv->height); | ||
| 65 | + | ||
| 66 | +- buffers = calloc((count + 1), sizeof(buffers[0])); | ||
| 67 | ++ /* Since we deduplicate attachments in the buffers array, there cannot be | ||
| 68 | ++ * more entries than there are attachments. | ||
| 69 | ++ */ | ||
| 70 | ++ buffers = calloc((min(count, DRI2BufferHiz) + 1), sizeof(buffers[0])); | ||
| 71 | + if (!buffers) | ||
| 72 | + goto err_out; | ||
| 73 | + | ||
| 74 | + do_get_buffers(DrawablePtr pDraw, int *width, int *height, | ||
| 75 | + const unsigned attachment = *(attachments++); | ||
| 76 | + const unsigned format = (has_format) ? *(attachments++) : 0; | ||
| 77 | + | ||
| 78 | ++ if (attachment > DRI2BufferHiz) | ||
| 79 | ++ goto err_out; | ||
| 80 | ++ | ||
| 81 | ++ if (attachments_bitset & (1u << attachment)) | ||
| 82 | ++ continue; | ||
| 83 | ++ | ||
| 84 | ++ attachments_bitset |= 1u << attachment; | ||
| 85 | ++ | ||
| 86 | + if (allocate_or_reuse_buffer(pDraw, ds, pPriv, attachment, | ||
| 87 | + format, dimensions_match, &buffers[i])) | ||
| 88 | + buffers_changed = 1; | ||
| 89 | + do_get_buffers(DrawablePtr pDraw, int *width, int *height, | ||
| 90 | + } | ||
| 91 | + | ||
| 92 | + if (attachment == DRI2BufferFrontLeft) { | ||
| 93 | +- have_real_front = TRUE; | ||
| 94 | + front_format = format; | ||
| 95 | + | ||
| 96 | + if (pDraw->type == DRAWABLE_WINDOW) | ||
| 97 | + need_fake_front = TRUE; | ||
| 98 | + } | ||
| 99 | +- | ||
| 100 | +- if (pDraw->type == DRAWABLE_WINDOW) { | ||
| 101 | +- if (attachment == DRI2BufferFakeFrontLeft) | ||
| 102 | +- have_fake_front = TRUE; | ||
| 103 | +- } | ||
| 104 | + } | ||
| 105 | + | ||
| 106 | +- if (need_real_front && !have_real_front) { | ||
| 107 | ++ if (need_real_front && | ||
| 108 | ++ !(attachments_bitset & (1u << DRI2BufferFrontLeft))) { | ||
| 109 | + if (allocate_or_reuse_buffer(pDraw, ds, pPriv, DRI2BufferFrontLeft, | ||
| 110 | + front_format, dimensions_match, | ||
| 111 | + &buffers[i])) | ||
| 112 | + do_get_buffers(DrawablePtr pDraw, int *width, int *height, | ||
| 113 | + i++; | ||
| 114 | + } | ||
| 115 | + | ||
| 116 | +- if (need_fake_front && !have_fake_front) { | ||
| 117 | ++ if (need_fake_front && | ||
| 118 | ++ !(attachments_bitset & (1u << DRI2BufferFakeFrontLeft))) { | ||
| 119 | + if (allocate_or_reuse_buffer(pDraw, ds, pPriv, DRI2BufferFakeFrontLeft, | ||
| 120 | + front_format, dimensions_match, | ||
| 121 | + &buffers[i])) | ||
| 122 | + do_get_buffers(DrawablePtr pDraw, int *width, int *height, | ||
| 123 | + goto err_out; | ||
| 124 | + | ||
| 125 | + i++; | ||
| 126 | +- have_fake_front = TRUE; | ||
| 127 | ++ attachments_bitset |= 1u << DRI2BufferFakeFrontLeft; | ||
| 128 | + } | ||
| 129 | + | ||
| 130 | + *out_count = i; | ||
| 131 | + do_get_buffers(DrawablePtr pDraw, int *width, int *height, | ||
| 132 | + * contents of the real front-buffer. This ensures correct operation of | ||
| 133 | + * applications that call glXWaitX before calling glDrawBuffer. | ||
| 134 | + */ | ||
| 135 | +- if (have_fake_front && buffers_changed) { | ||
| 136 | ++ if (buffers_changed && | ||
| 137 | ++ (attachments_bitset & (1u << DRI2BufferFakeFrontLeft))) { | ||
| 138 | + BoxRec box; | ||
| 139 | + RegionRec region; | ||
| 140 | + | ||
| 141 | +-- | ||
| 142 | +2.33.0 | ||
| 143 | + | ||
| @@ -0,0 +1,93 @@ | |||
| 1 | +From a569eb4f36ed96a9e445ececd7e8d98c223461a0 Mon Sep 17 00:00:00 2001 | ||
| 2 | +From: Peter Hutterer <peter.hutterer@who-t.net> | ||
| 3 | +Date: Wed, 29 Apr 2026 05:40:33 +0000 | ||
| 4 | +Subject: [PATCH] dix: increase XLFDMAXFONTNAMELEN to match libXfont2's | ||
| 5 | + MAXFONTNAMELEN | ||
| 6 | + | ||
| 7 | +XLFDMAXFONTNAMELEN was 256 bytes, but libXfont2 defines MAXFONTNAMELEN | ||
| 8 | +as 1024 and allows font names and alias targets up to that length in | ||
| 9 | +fonts.alias files. | ||
| 10 | + | ||
| 11 | +doListFontsAndAliases copies the resolved alias target into a | ||
| 12 | +stack-allocated tmp_pattern[XLFDMAXFONTNAMELEN] and then into | ||
| 13 | +c->current.pattern[XLFDMAXFONTNAMELEN] (defined in LFWIstateRec). | ||
| 14 | +doListFontsWithInfo has the same pattern, copying the resolved name into | ||
| 15 | +c->current.pattern[]. With the old 256-byte limit, a fonts.alias entry | ||
| 16 | +with a target name between 257 and 1023 bytes would overflow both | ||
| 17 | +buffers. | ||
| 18 | + | ||
| 19 | +An attacker can exploit this by: | ||
| 20 | + 1. Creating a font directory with a fonts.alias containing an alias | ||
| 21 | + whose target name exceeds 256 bytes | ||
| 22 | + 2. Using SetFontPath to add the malicious directory | ||
| 23 | + 3. Calling ListFonts with the alias name to trigger alias resolution | ||
| 24 | + 4. The oversized resolved name overflows the 256-byte stack buffer | ||
| 25 | + | ||
| 26 | +Increase XLFDMAXFONTNAMELEN from 256 to 1024 to match libXfont2's | ||
| 27 | +MAXFONTNAMELEN, ensuring the server can handle any name the font library | ||
| 28 | +produces. | ||
| 29 | + | ||
| 30 | +This vulnerability was discovered by: | ||
| 31 | +Anonymous working with TrendAI Zero Day Initiative | ||
| 32 | + | ||
| 33 | +ZDI-CAN-30136 | ||
| 34 | + | ||
| 35 | +Assisted-by: Claude:claude-opus-4-6 | ||
| 36 | +(cherry picked from commit bb5158f962dc935e58ef8b4b5fcb31be201a6e07) | ||
| 37 | + | ||
| 38 | +Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2229> | ||
| 39 | + | ||
| 40 | +Reference:https://gitlab.freedesktop.org/xorg/xserver/-/commit/a569eb4f36ed96a9e445ececd7e8d98c223461a0 | ||
| 41 | +Conflict:Adapt context | ||
| 42 | +--- | ||
| 43 | + dix/dixfonts.c | 8 ++++++++ | ||
| 44 | + include/closestr.h | 7 ++++++- | ||
| 45 | + 2 files changed, 14 insertions(+), 1 deletion(-) | ||
| 46 | + | ||
| 47 | +diff --git a/dix/dixfonts.c b/dix/dixfonts.c | ||
| 48 | +index 0ea8678..386c386 100644 | ||
| 49 | +--- a/dix/dixfonts.c | ||
| 50 | ++++ b/dix/dixfonts.c | ||
| 51 | + doListFontsAndAliases(ClientPtr client, LFclosurePtr c) | ||
| 52 | + * is BadFontName, indicating the alias resolution | ||
| 53 | + * is complete. | ||
| 54 | + */ | ||
| 55 | ++ if (resolvedlen > XLFDMAXFONTNAMELEN) { | ||
| 56 | ++ err = BadFontName; | ||
| 57 | ++ goto ContBadFontName; | ||
| 58 | ++ } | ||
| 59 | + memmove(tmp_pattern, resolved, resolvedlen); | ||
| 60 | + if (c->haveSaved) { | ||
| 61 | + char *tmpname; | ||
| 62 | + doListFontsWithInfo(ClientPtr client, LFWIclosurePtr c) | ||
| 63 | + memmove(c->savedName, name, namelen + 1); | ||
| 64 | + aliascount = 20; | ||
| 65 | + } | ||
| 66 | ++ if (namelen > XLFDMAXFONTNAMELEN) { | ||
| 67 | ++ err = BadFontName; | ||
| 68 | ++ goto ContBadFontName; | ||
| 69 | ++ } | ||
| 70 | + memmove(c->current.pattern, name, namelen); | ||
| 71 | + c->current.patlen = namelen; | ||
| 72 | + c->current.max_names = 1; | ||
| 73 | +diff --git a/include/closestr.h b/include/closestr.h | ||
| 74 | +index 60e6f09..7567ac6 100644 | ||
| 75 | +--- a/include/closestr.h | ||
| 76 | ++++ b/include/closestr.h | ||
| 77 | + typedef struct _OFclosure { | ||
| 78 | + | ||
| 79 | + /* ListFontsWithInfo */ | ||
| 80 | + | ||
| 81 | +-#define XLFDMAXFONTNAMELEN 256 | ||
| 82 | ++/* libXfont2 allows font names/aliases up to MAXFONTNAMELEN (1024) bytes in | ||
| 83 | ++ * fonts.alias files. The server's pattern buffers must be large enough to | ||
| 84 | ++ * hold resolved alias targets returned by the font library. | ||
| 85 | ++ * ZDI-CAN-30136 | ||
| 86 | ++ */ | ||
| 87 | ++#define XLFDMAXFONTNAMELEN 1024 | ||
| 88 | + typedef struct _LFWIstate { | ||
| 89 | + char pattern[XLFDMAXFONTNAMELEN]; | ||
| 90 | + int patlen; | ||
| 91 | +-- | ||
| 92 | +2.33.0 | ||
| 93 | + | ||
| @@ -0,0 +1,125 @@ | |||
| 1 | +From f304b57444be3991fd9d3389f309c6eeb056a6c4 Mon Sep 17 00:00:00 2001 | ||
| 2 | +From: Peter Hutterer <peter.hutterer@who-t.net> | ||
| 3 | +Date: Mon, 20 Apr 2026 11:16:13 +1000 | ||
| 4 | +Subject: [PATCH] sync: fix deletion of counters and fences | ||
| 5 | + | ||
| 6 | +Both FreeCounter() and miSyncDestroyFence() iterate over the trigger list | ||
| 7 | +and invoke the CounterDestroyed callback on each trigger. | ||
| 8 | + | ||
| 9 | +The CounterDestroyed callback (e.g. SyncAwaitTriggerFired) may call | ||
| 10 | +FreeResource/FreeAwait, which frees the SyncAwaitUnion containing all | ||
| 11 | +SyncAwait structs in the same Await group. | ||
| 12 | + | ||
| 13 | +When multiple conditions in a single Await reference the same sync | ||
| 14 | +object (counter or fence), the first callback frees all SyncAwait | ||
| 15 | +structs while subsequent trigger list nodes still reference them. On the | ||
| 16 | +next iteration, reading ptl->next or ptl->pTrigger dereferences freed | ||
| 17 | +memory, leading to a use-after-free. | ||
| 18 | + | ||
| 19 | +We need separate fixes for separate issues here to fix this in one go | ||
| 20 | +- use our null-terminated list macro to make sure our next pointer stays | ||
| 21 | + valid (the code accessed ptl->next after freeing it) | ||
| 22 | +- update the list head before deleting the trigger, eventually this ends | ||
| 23 | + up being NULL anyway but meanwhile the list head is a valid list | ||
| 24 | + during CounterDestroyed | ||
| 25 | +- check if we actually do have a trigger before dereferencing the | ||
| 26 | + callback | ||
| 27 | +- Set all triggers to NULL if they are shared so we don't dereference | ||
| 28 | + potentially freed memory | ||
| 29 | + | ||
| 30 | +This vulnerability was discovered by: | ||
| 31 | +Anonymous working with TrendAI Zero Day Initiative | ||
| 32 | + | ||
| 33 | +ZDI-CAN-30159 (miSyncDestroyFence), ZDI-CAN-30163 (FreeCounter) | ||
| 34 | + | ||
| 35 | +Assisted-by: Claude:claude-opus-4-6 | ||
| 36 | +(cherry picked from commit f5abfb61994471023d8c6470428c8e30c411cc0b) | ||
| 37 | + | ||
| 38 | +Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2229> | ||
| 39 | + | ||
| 40 | +Reference:https://gitlab.freedesktop.org/xorg/xserver/-/commit/f304b57444be3991fd9d3389f309c6eeb056a6c4 | ||
| 41 | +Conflict:no | ||
| 42 | +--- | ||
| 43 | + Xext/sync.c | 32 +++++++++++++++++++++++++------- | ||
| 44 | + miext/sync/misync.c | 12 ++++++++---- | ||
| 45 | + 2 files changed, 33 insertions(+), 11 deletions(-) | ||
| 46 | + | ||
| 47 | +diff --git a/Xext/sync.c b/Xext/sync.c | ||
| 48 | +index 900858773..f4f1036d1 100644 | ||
| 49 | +--- a/Xext/sync.c | ||
| 50 | ++++ b/Xext/sync.c | ||
| 51 | + FreeCounter(void *env, XID id) | ||
| 52 | + SyncTriggerList *ptl, *pnext; | ||
| 53 | + | ||
| 54 | + /* tell all the counter's triggers that counter has been destroyed */ | ||
| 55 | +- for (ptl = pCounter->sync.pTriglist; ptl; ptl = pnext) { | ||
| 56 | +- (*ptl->pTrigger->CounterDestroyed) (ptl->pTrigger); | ||
| 57 | +- pnext = ptl->next; | ||
| 58 | ++ nt_list_for_each_entry_safe(ptl, pnext, pCounter->sync.pTriglist, next) { | ||
| 59 | ++ /* Remove it from the list first so CounterDestroyed | ||
| 60 | ++ * callbacks have a valid list to iterate */ | ||
| 61 | ++ pCounter->sync.pTriglist = pnext; | ||
| 62 | ++ if (ptl->pTrigger) | ||
| 63 | ++ (*ptl->pTrigger->CounterDestroyed) (ptl->pTrigger); | ||
| 64 | + free(ptl); /* destroy the trigger list as we go */ | ||
| 65 | + } | ||
| 66 | + if (IsSystemCounter(pCounter)) { | ||
| 67 | + FreeAwait(void *addr, XID id) | ||
| 68 | + | ||
| 69 | + for (numwaits = pAwaitUnion->header.num_waitconditions; numwaits; | ||
| 70 | + numwaits--, pAwait++) { | ||
| 71 | +- /* If the counter is being destroyed, FreeCounter will delete | ||
| 72 | +- * the trigger list itself, so don't do it here. | ||
| 73 | ++ /* If the counter is being destroyed, FreeCounter/miSyncDestroyFence | ||
| 74 | ++ * will delete the trigger list itself, so don't do it here. | ||
| 75 | ++ * However, we must NULL out the pTrigger pointer in the trigger list | ||
| 76 | ++ * node so the destroy loop knows not to dereference it - the backing | ||
| 77 | ++ * SyncAwait memory is about to be freed below. | ||
| 78 | + */ | ||
| 79 | + SyncObject *pSync = pAwait->trigger.pSync; | ||
| 80 | + | ||
| 81 | +- if (pSync && !pSync->beingDestroyed) | ||
| 82 | +- SyncDeleteTriggerFromSyncObject(&pAwait->trigger); | ||
| 83 | ++ if (pSync) { | ||
| 84 | ++ if (!pSync->beingDestroyed) { | ||
| 85 | ++ SyncDeleteTriggerFromSyncObject(&pAwait->trigger); | ||
| 86 | ++ } else { | ||
| 87 | ++ SyncTriggerList *ptl; | ||
| 88 | ++ | ||
| 89 | ++ nt_list_for_each_entry(ptl, pSync->pTriglist, next) { | ||
| 90 | ++ if (ptl->pTrigger == &pAwait->trigger) { | ||
| 91 | ++ ptl->pTrigger = NULL; | ||
| 92 | ++ break; | ||
| 93 | ++ } | ||
| 94 | ++ } | ||
| 95 | ++ } | ||
| 96 | ++ } | ||
| 97 | + } | ||
| 98 | + free(pAwaitUnion); | ||
| 99 | + return Success; | ||
| 100 | +diff --git a/miext/sync/misync.c b/miext/sync/misync.c | ||
| 101 | +index 9a6fbbd4a..4ce249850 100644 | ||
| 102 | +--- a/miext/sync/misync.c | ||
| 103 | ++++ b/miext/sync/misync.c | ||
| 104 | + miSyncDestroyFence(SyncFence * pFence) | ||
| 105 | + SyncScreenPrivPtr pScreenPriv = SYNC_SCREEN_PRIV(pScreen); | ||
| 106 | + SyncTriggerList *ptl, *pNext; | ||
| 107 | + | ||
| 108 | +- /* tell all the fence's triggers that the counter has been destroyed */ | ||
| 109 | +- for (ptl = pFence->sync.pTriglist; ptl; ptl = pNext) { | ||
| 110 | +- (*ptl->pTrigger->CounterDestroyed) (ptl->pTrigger); | ||
| 111 | +- pNext = ptl->next; | ||
| 112 | ++ /* tell all the fence's triggers that the fence has been destroyed. | ||
| 113 | ++ * Update pTriglist before each callback and free so that FreeAwait | ||
| 114 | ++ * sees a valid list head when scanning for triggers to NULL out. | ||
| 115 | ++ */ | ||
| 116 | ++ nt_list_for_each_entry_safe(ptl, pNext, pFence->sync.pTriglist, next) { | ||
| 117 | ++ pFence->sync.pTriglist = pNext; | ||
| 118 | ++ if (ptl->pTrigger) | ||
| 119 | ++ (*ptl->pTrigger->CounterDestroyed) (ptl->pTrigger); | ||
| 120 | + free(ptl); /* destroy the trigger list as we go */ | ||
| 121 | + } | ||
| 122 | + | ||
| 123 | +-- | ||
| 124 | +2.33.0 | ||
| 125 | + | ||
| @@ -0,0 +1,53 @@ | |||
| 1 | +From eced7e74cad4a46c3a3c17b2df13b70b8bedfc25 Mon Sep 17 00:00:00 2001 | ||
| 2 | +From: Peter Hutterer <peter.hutterer@who-t.net> | ||
| 3 | +Date: Mon, 20 Apr 2026 11:17:41 +1000 | ||
| 4 | +Subject: [PATCH] xkb: reject key types with num_levels exceeding | ||
| 5 | + XkbMaxShiftLevel | ||
| 6 | + | ||
| 7 | +CheckKeyTypes validates incoming key type definitions from XkbSetMap | ||
| 8 | +requests but does not enforce an upper bound on numLevels. A client can set | ||
| 9 | +numLevels up to 255 on a non-canonical key type, which is stored in the | ||
| 10 | +server's type table. | ||
| 11 | + | ||
| 12 | +When ChangeKeyboardMapping later triggers XkbUpdateKeyTypesFromCore, the | ||
| 13 | +function XkbKeyTypesForCoreSymbols computes groupsWidth from num_levels and | ||
| 14 | +uses the XKB_OFFSET(g, l) = (g * groupsWidth) + l macro to index into | ||
| 15 | +tsyms[], a stack-allocated buffer of XkbMaxSymsPerKey (252) entries. With | ||
| 16 | +num_levels=255, groupsWidth=255, and indices reach up to 3*255+254 = 1019, | ||
| 17 | +overflowing the 252-element stack buffer by 767 KeySym-sized entries. | ||
| 18 | + | ||
| 19 | +Fix by rejecting numLevels values greater than XkbMaxShiftLevel (63) in | ||
| 20 | +CheckKeyTypes, alongside the existing lower-bound check for numLevels < 1. | ||
| 21 | + | ||
| 22 | +This vulnerability was discovered by: | ||
| 23 | +Anonymous working with TrendAI Zero Day Initiative | ||
| 24 | + | ||
| 25 | +ZDI-CAN-30160 | ||
| 26 | + | ||
| 27 | +Assisted-by: Claude:claude-opus-4-6 | ||
| 28 | +(cherry picked from commit 543e108516428fc8c3bea91d6563ad266f9a801e) | ||
| 29 | + | ||
| 30 | +Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2229> | ||
| 31 | + | ||
| 32 | +Reference:https://gitlab.freedesktop.org/xorg/xserver/-/commit/eced7e74cad4a46c3a3c17b2df13b70b8bedfc25 | ||
| 33 | +Conflict:no | ||
| 34 | +--- | ||
| 35 | + xkb/xkb.c | 2 +- | ||
| 36 | + 1 file changed, 1 insertion(+), 1 deletion(-) | ||
| 37 | + | ||
| 38 | +diff --git a/xkb/xkb.c b/xkb/xkb.c | ||
| 39 | +index d0d1b77cb..2b5027104 100644 | ||
| 40 | +--- a/xkb/xkb.c | ||
| 41 | ++++ b/xkb/xkb.c | ||
| 42 | + CheckKeyTypes(ClientPtr client, | ||
| 43 | + } | ||
| 44 | + n = i + req->firstType; | ||
| 45 | + width = wire->numLevels; | ||
| 46 | +- if (width < 1) { | ||
| 47 | ++ if (width < 1 || width > XkbMaxShiftLevel) { | ||
| 48 | + *nMapsRtrn = _XkbErrCode3(0x04, n, width); | ||
| 49 | + return 0; | ||
| 50 | + } | ||
| 51 | +-- | ||
| 52 | +2.33.0 | ||
| 53 | + | ||
| @@ -0,0 +1,55 @@ | |||
| 1 | +From 54c3d9fad0f2f97835da9d275b53255f4963029f Mon Sep 17 00:00:00 2001 | ||
| 2 | +From: Peter Hutterer <peter.hutterer@who-t.net> | ||
| 3 | +Date: Mon, 20 Apr 2026 11:18:13 +1000 | ||
| 4 | +Subject: [PATCH] xkb: clamp nMaps to mapWidths buffer size in CheckKeyTypes | ||
| 5 | + | ||
| 6 | +CheckKeyTypes computes nMaps = firstType + nTypes from client-controlled | ||
| 7 | +request fields when XkbSetMapResizeTypes is set. This value is used to | ||
| 8 | +index mapWidths[], a stack-allocated CARD8 array of XkbMaxLegalKeyCode + 1 | ||
| 9 | +(256) elements. No upper bound is enforced on nMaps. | ||
| 10 | + | ||
| 11 | +An attacker can first send SetMap(firstType=0, nTypes=255, ResizeTypes) to | ||
| 12 | +set the server's num_types to 255, then send SetMap(firstType=255, | ||
| 13 | +nTypes=10, ResizeTypes). The firstType > num_types check passes because | ||
| 14 | +255 > 255 is false (the check uses > rather than >=). nMaps is then | ||
| 15 | +computed as 265, and the loop writes mapWidths[255..264], overflowing 9 | ||
| 16 | +bytes past the stack buffer into adjacent stack variables (symsPerKey[]). | ||
| 17 | + | ||
| 18 | +Fix by rejecting requests where firstType + nTypes would exceed the | ||
| 19 | +mapWidths buffer size (XkbMaxLegalKeyCode + 1). | ||
| 20 | + | ||
| 21 | +This vulnerability was discovered by: | ||
| 22 | +Anonymous working with TrendAI Zero Day Initiative | ||
| 23 | + | ||
| 24 | +ZDI-CAN-30161 | ||
| 25 | + | ||
| 26 | +Assisted-by: Claude:claude-opus-4-6 | ||
| 27 | +(cherry picked from commit 867b59b33bee669cb412f1314e47c52eacf6e00b) | ||
| 28 | + | ||
| 29 | +Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2229> | ||
| 30 | + | ||
| 31 | +Reference:https://gitlab.freedesktop.org/xorg/xserver/-/commit/54c3d9fad0f2f97835da9d275b53255f4963029f | ||
| 32 | +Conflict:no | ||
| 33 | +--- | ||
| 34 | + xkb/xkb.c | 5 +++++ | ||
| 35 | + 1 file changed, 5 insertions(+) | ||
| 36 | + | ||
| 37 | +diff --git a/xkb/xkb.c b/xkb/xkb.c | ||
| 38 | +index 2b5027104..fad39f9a9 100644 | ||
| 39 | +--- a/xkb/xkb.c | ||
| 40 | ++++ b/xkb/xkb.c | ||
| 41 | + CheckKeyTypes(ClientPtr client, | ||
| 42 | + *nMapsRtrn = _XkbErrCode4(0x02, req->firstType, req->nTypes, 4); | ||
| 43 | + return 0; | ||
| 44 | + } | ||
| 45 | ++ if (nMaps > XkbMaxLegalKeyCode + 1) { | ||
| 46 | ++ *nMapsRtrn = _XkbErrCode4(0x02, req->firstType, req->nTypes, | ||
| 47 | ++ XkbMaxLegalKeyCode + 1); | ||
| 48 | ++ return 0; | ||
| 49 | ++ } | ||
| 50 | + } | ||
| 51 | + else if (req->present & XkbKeyTypesMask) { | ||
| 52 | + nMaps = xkb->map->num_types; | ||
| 53 | +-- | ||
| 54 | +2.33.0 | ||
| 55 | + | ||
| @@ -0,0 +1,74 @@ | |||
| 1 | +From 92a167ab3fda0bee41cf97f6a40a4c01c67d85d4 Mon Sep 17 00:00:00 2001 | ||
| 2 | +From: Peter Hutterer <peter.hutterer@who-t.net> | ||
| 3 | +Date: Mon, 20 Apr 2026 11:17:08 +1000 | ||
| 4 | +Subject: [PATCH] sync: restart trigger list iteration in SyncChangeCounter | ||
| 5 | + after TriggerFired | ||
| 6 | + | ||
| 7 | +This is the equivalent check to miSyncTriggerFence() from | ||
| 8 | +commit f19ab94ba9c8 ("miext/sync: Fix use-after-free in miSyncTriggerFence()") | ||
| 9 | + | ||
| 10 | +When a trigger fires via SyncAwaitTriggerFired, the resulting | ||
| 11 | +FreeResource/FreeAwait call invokes SyncDeleteTriggerFromSyncObject for | ||
| 12 | +every trigger in the same Await group. This unlinks and frees the | ||
| 13 | +corresponding trigger list nodes - potentially including the node pnext | ||
| 14 | +points to. | ||
| 15 | + | ||
| 16 | +Fix by restarting iteration from the list head after a trigger fires, since | ||
| 17 | +TriggerFired may have arbitrarily mutated the list. Triggers that have fired | ||
| 18 | +are removed from the list by FreeAwait, so restarting cannot cause infinite | ||
| 19 | +loops. | ||
| 20 | + | ||
| 21 | +This vulnerability was discovered by: | ||
| 22 | +Anonymous working with TrendAI Zero Day Initiative | ||
| 23 | + | ||
| 24 | +ZDI-CAN-30164 | ||
| 25 | + | ||
| 26 | +Assisted-by: Claude:claude-opus-4-6 | ||
| 27 | +(cherry picked from commit bdd7bf57af208b1ddf57d4683d67104443b44812) | ||
| 28 | + | ||
| 29 | +Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2229> | ||
| 30 | + | ||
| 31 | +Reference:https://gitlab.freedesktop.org/xorg/xserver/-/commit/92a167ab3fda0bee41cf97f6a40a4c01c67d85d4 | ||
| 32 | +Conflict:no | ||
| 33 | +--- | ||
| 34 | + Xext/sync.c | 23 ++++++++++++++++++++++- | ||
| 35 | + 1 file changed, 22 insertions(+), 1 deletion(-) | ||
| 36 | + | ||
| 37 | +diff --git a/Xext/sync.c b/Xext/sync.c | ||
| 38 | +index f4f1036d1..0e70dd08a 100644 | ||
| 39 | +--- a/Xext/sync.c | ||
| 40 | ++++ b/Xext/sync.c | ||
| 41 | + SyncChangeCounter(SyncCounter * pCounter, int64_t newval) | ||
| 42 | + /* run through triggers to see if any become true */ | ||
| 43 | + for (ptl = pCounter->sync.pTriglist; ptl; ptl = pnext) { | ||
| 44 | + pnext = ptl->next; | ||
| 45 | +- if ((*ptl->pTrigger->CheckTrigger) (ptl->pTrigger, oldval)) | ||
| 46 | ++ if ((*ptl->pTrigger->CheckTrigger) (ptl->pTrigger, oldval)) { | ||
| 47 | + (*ptl->pTrigger->TriggerFired) (ptl->pTrigger); | ||
| 48 | ++ /* TriggerFired may have called SyncDeleteTriggerFromSyncObject | ||
| 49 | ++ * for sibling triggers in the same Await group, freeing their | ||
| 50 | ++ * trigger list nodes - potentially including pnext. Verify | ||
| 51 | ++ * pnext is still on the counter's trigger list; if not, | ||
| 52 | ++ * restart from the list head. | ||
| 53 | ++ * | ||
| 54 | ++ * Unlike miSyncTriggerFence() we cannot use a do/while | ||
| 55 | ++ * restart loop here: counter trigger lists may contain alarm | ||
| 56 | ++ * triggers which are not removed after firing and would cause | ||
| 57 | ++ * an infinite loop when delta is 0. | ||
| 58 | ++ */ | ||
| 59 | ++ if (pnext) { | ||
| 60 | ++ SyncTriggerList *tmp; | ||
| 61 | ++ for (tmp = pCounter->sync.pTriglist; tmp; tmp = tmp->next) { | ||
| 62 | ++ if (tmp == pnext) | ||
| 63 | ++ break; | ||
| 64 | ++ } | ||
| 65 | ++ if (!tmp) | ||
| 66 | ++ pnext = pCounter->sync.pTriglist; | ||
| 67 | ++ } | ||
| 68 | ++ } | ||
| 69 | + } | ||
| 70 | + | ||
| 71 | + if (IsSystemCounter(pCounter)) { | ||
| 72 | +-- | ||
| 73 | +2.33.0 | ||
| 74 | + | ||
| @@ -0,0 +1,156 @@ | |||
| 1 | +From 94341bd715d62ba8da4c1851f517018996da1af8 Mon Sep 17 00:00:00 2001 | ||
| 2 | +From: Peter Hutterer <peter.hutterer@who-t.net> | ||
| 3 | +Date: Mon, 20 Apr 2026 11:18:48 +1000 | ||
| 4 | +Subject: [PATCH] glx: fix reversed length check in ChangeDrawableAttributes | ||
| 5 | + | ||
| 6 | +The request length validation in __glXDisp_ChangeDrawableAttributes and | ||
| 7 | +__glXDispSwap_ChangeDrawableAttributes uses the wrong comparison direction. | ||
| 8 | +The check tests whether the computed request size is LESS THAN | ||
| 9 | +client->req_len, but should test whether it is GREATER THAN. With the | ||
| 10 | +reversed operator, an undersized request (where numAttribs claims more | ||
| 11 | +attribute pairs than the request actually contains) passes validation. | ||
| 12 | + | ||
| 13 | +DoChangeDrawableAttributes then iterates numAttribs attribute pairs starting | ||
| 14 | +from the end of the request header, reading past the actual request data | ||
| 15 | +into adjacent memory. This is an out-of-bounds read that can also cause | ||
| 16 | +an out-of-bounds write when a GLX_EVENT_MASK attribute key is found in the | ||
| 17 | +overread data and its corresponding value is written to pGlxDraw->eventMask. | ||
| 18 | + | ||
| 19 | +This patch effectively reverts commit 402b329c3aa8 ("glx: Work around | ||
| 20 | +wrong request lengths sent by mesa"). This was fixed in mesa commit | ||
| 21 | +4324d6fdfbba1 in 2011 (mesa 7.11). | ||
| 22 | + | ||
| 23 | +Fixes: 402b329c3aa8 ("glx: Work around wrong request lengths sent by mesa") | ||
| 24 | + | ||
| 25 | +This vulnerability was discovered by: | ||
| 26 | +Anonymous working with TrendAI Zero Day Initiative | ||
| 27 | + | ||
| 28 | +ZDI-CAN-30165 | ||
| 29 | + | ||
| 30 | +Assisted-by: Claude:claude-opus-4-6 | ||
| 31 | +(cherry picked from commit 6d459e4daf715bea8abdafa8fb130be2f8a1d145) | ||
| 32 | + | ||
| 33 | +Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2229> | ||
| 34 | + | ||
| 35 | +Reference:https://gitlab.freedesktop.org/xorg/xserver/-/commit/94341bd715d62ba8da4c1851f517018996da1af8 | ||
| 36 | +Conflict:no | ||
| 37 | +--- | ||
| 38 | + glx/glxcmds.c | 21 +++++---------------- | ||
| 39 | + glx/glxcmdsswap.c | 12 +++++------- | ||
| 40 | + 2 files changed, 10 insertions(+), 23 deletions(-) | ||
| 41 | + | ||
| 42 | +diff --git a/glx/glxcmds.c b/glx/glxcmds.c | ||
| 43 | +index 1e46d0c72..8a13e34b5 100644 | ||
| 44 | +--- a/glx/glxcmds.c | ||
| 45 | ++++ b/glx/glxcmds.c | ||
| 46 | + __glXDisp_GetFBConfigsSGIX(__GLXclientState * cl, GLbyte * pc) | ||
| 47 | + ClientPtr client = cl->client; | ||
| 48 | + xGLXGetFBConfigsSGIXReq *req = (xGLXGetFBConfigsSGIXReq *) pc; | ||
| 49 | + | ||
| 50 | +- /* work around mesa bug, don't use REQUEST_SIZE_MATCH */ | ||
| 51 | +- REQUEST_AT_LEAST_SIZE(xGLXGetFBConfigsSGIXReq); | ||
| 52 | ++ REQUEST_SIZE_MATCH(xGLXGetFBConfigsSGIXReq); | ||
| 53 | + return DoGetFBConfigs(cl, req->screen); | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | + __glXDisp_DestroyPixmap(__GLXclientState * cl, GLbyte * pc) | ||
| 57 | + ClientPtr client = cl->client; | ||
| 58 | + xGLXDestroyPixmapReq *req = (xGLXDestroyPixmapReq *) pc; | ||
| 59 | + | ||
| 60 | +- /* should be REQUEST_SIZE_MATCH, but mesa's glXDestroyPixmap used to set | ||
| 61 | +- * length to 3 instead of 2 */ | ||
| 62 | +- REQUEST_AT_LEAST_SIZE(xGLXDestroyPixmapReq); | ||
| 63 | ++ REQUEST_SIZE_MATCH(xGLXDestroyPixmapReq); | ||
| 64 | + | ||
| 65 | + return DoDestroyDrawable(cl, req->glxpixmap, GLX_DRAWABLE_PIXMAP); | ||
| 66 | + } | ||
| 67 | + __glXDisp_ChangeDrawableAttributes(__GLXclientState * cl, GLbyte * pc) | ||
| 68 | + client->errorValue = req->numAttribs; | ||
| 69 | + return BadValue; | ||
| 70 | + } | ||
| 71 | +-#if 0 | ||
| 72 | +- /* mesa sends an additional 8 bytes */ | ||
| 73 | ++ | ||
| 74 | + REQUEST_FIXED_SIZE(xGLXChangeDrawableAttributesReq, req->numAttribs << 3); | ||
| 75 | +-#else | ||
| 76 | +- if (((sizeof(xGLXChangeDrawableAttributesReq) + | ||
| 77 | +- (req->numAttribs << 3)) >> 2) < client->req_len) | ||
| 78 | +- return BadLength; | ||
| 79 | +-#endif | ||
| 80 | + | ||
| 81 | + return DoChangeDrawableAttributes(cl->client, req->drawable, | ||
| 82 | + req->numAttribs, (CARD32 *) (req + 1)); | ||
| 83 | + __glXDisp_DestroyWindow(__GLXclientState * cl, GLbyte * pc) | ||
| 84 | + ClientPtr client = cl->client; | ||
| 85 | + xGLXDestroyWindowReq *req = (xGLXDestroyWindowReq *) pc; | ||
| 86 | + | ||
| 87 | +- /* mesa's glXDestroyWindow used to set length to 3 instead of 2 */ | ||
| 88 | +- REQUEST_AT_LEAST_SIZE(xGLXDestroyWindowReq); | ||
| 89 | ++ REQUEST_SIZE_MATCH(xGLXDestroyWindowReq); | ||
| 90 | + | ||
| 91 | + return DoDestroyDrawable(cl, req->glxwindow, GLX_DRAWABLE_WINDOW); | ||
| 92 | + } | ||
| 93 | + __glXDisp_GetDrawableAttributes(__GLXclientState * cl, GLbyte * pc) | ||
| 94 | + ClientPtr client = cl->client; | ||
| 95 | + xGLXGetDrawableAttributesReq *req = (xGLXGetDrawableAttributesReq *) pc; | ||
| 96 | + | ||
| 97 | +- /* this should be REQUEST_SIZE_MATCH, but mesa sends an additional 4 bytes */ | ||
| 98 | +- REQUEST_AT_LEAST_SIZE(xGLXGetDrawableAttributesReq); | ||
| 99 | ++ REQUEST_SIZE_MATCH(xGLXGetDrawableAttributesReq); | ||
| 100 | + | ||
| 101 | + return DoGetDrawableAttributes(cl, req->drawable); | ||
| 102 | + } | ||
| 103 | +diff --git a/glx/glxcmdsswap.c b/glx/glxcmdsswap.c | ||
| 104 | +index 7d6674470..96382672a 100644 | ||
| 105 | +--- a/glx/glxcmdsswap.c | ||
| 106 | ++++ b/glx/glxcmdsswap.c | ||
| 107 | + __glXDispSwap_GetFBConfigsSGIX(__GLXclientState * cl, GLbyte * pc) | ||
| 108 | + | ||
| 109 | + __GLX_DECLARE_SWAP_VARIABLES; | ||
| 110 | + | ||
| 111 | +- REQUEST_AT_LEAST_SIZE(xGLXGetFBConfigsSGIXReq); | ||
| 112 | ++ REQUEST_SIZE_MATCH(xGLXGetFBConfigsSGIXReq); | ||
| 113 | + | ||
| 114 | + __GLX_SWAP_INT(&req->screen); | ||
| 115 | + return __glXDisp_GetFBConfigsSGIX(cl, pc); | ||
| 116 | + __glXDispSwap_DestroyPixmap(__GLXclientState * cl, GLbyte * pc) | ||
| 117 | + | ||
| 118 | + __GLX_DECLARE_SWAP_VARIABLES; | ||
| 119 | + | ||
| 120 | +- REQUEST_AT_LEAST_SIZE(xGLXDestroyGLXPixmapReq); | ||
| 121 | ++ REQUEST_SIZE_MATCH(xGLXDestroyGLXPixmapReq); | ||
| 122 | + | ||
| 123 | + __GLX_SWAP_SHORT(&req->length); | ||
| 124 | + __GLX_SWAP_INT(&req->glxpixmap); | ||
| 125 | + __glXDispSwap_ChangeDrawableAttributes(__GLXclientState * cl, GLbyte * pc) | ||
| 126 | + client->errorValue = req->numAttribs; | ||
| 127 | + return BadValue; | ||
| 128 | + } | ||
| 129 | +- if (((sizeof(xGLXChangeDrawableAttributesReq) + | ||
| 130 | +- (req->numAttribs << 3)) >> 2) < client->req_len) | ||
| 131 | +- return BadLength; | ||
| 132 | ++ REQUEST_FIXED_SIZE(xGLXChangeDrawableAttributesReq, req->numAttribs << 3); | ||
| 133 | + | ||
| 134 | + attribs = (CARD32 *) (req + 1); | ||
| 135 | + __GLX_SWAP_INT_ARRAY(attribs, req->numAttribs << 1); | ||
| 136 | + __glXDispSwap_DestroyWindow(__GLXclientState * cl, GLbyte * pc) | ||
| 137 | + | ||
| 138 | + __GLX_DECLARE_SWAP_VARIABLES; | ||
| 139 | + | ||
| 140 | +- REQUEST_AT_LEAST_SIZE(xGLXDestroyWindowReq); | ||
| 141 | ++ REQUEST_SIZE_MATCH(xGLXDestroyWindowReq); | ||
| 142 | + | ||
| 143 | + __GLX_SWAP_INT(&req->glxwindow); | ||
| 144 | + | ||
| 145 | + __glXDispSwap_GetDrawableAttributes(__GLXclientState * cl, GLbyte * pc) | ||
| 146 | + | ||
| 147 | + __GLX_DECLARE_SWAP_VARIABLES; | ||
| 148 | + | ||
| 149 | +- REQUEST_AT_LEAST_SIZE(xGLXGetDrawableAttributesReq); | ||
| 150 | ++ REQUEST_SIZE_MATCH(xGLXGetDrawableAttributesReq); | ||
| 151 | + | ||
| 152 | + __GLX_SWAP_SHORT(&req->length); | ||
| 153 | + __GLX_SWAP_INT(&req->drawable); | ||
| 154 | +-- | ||
| 155 | +2.33.0 | ||
| 156 | + | ||
| @@ -0,0 +1,77 @@ | |||
| 1 | +From 182c23f780402062ab31963776a19d5b87e25ac8 Mon Sep 17 00:00:00 2001 | ||
| 2 | +From: Peter Hutterer <peter.hutterer@who-t.net> | ||
| 3 | +Date: Mon, 20 Apr 2026 11:19:20 +1000 | ||
| 4 | +Subject: [PATCH] saver: re-fetch screen private after CheckScreenPrivate in | ||
| 5 | + CreateSaverWindow | ||
| 6 | +MIME-Version: 1.0 | ||
| 7 | +Content-Type: text/plain; charset=UTF-8 | ||
| 8 | +Content-Transfer-Encoding: 8bit | ||
| 9 | + | ||
| 10 | +CreateSaverWindow stores pPriv (the ScreenSaverScreenPrivatePtr) in a local | ||
| 11 | +variable via the SetupScreen macro at function entry. When an existing saver | ||
| 12 | +window is being replaced, the function sets pPriv->hasWindow = FALSE and | ||
| 13 | +calls CheckScreenPrivate(). If at this point pPriv->attr is NULL (cleared | ||
| 14 | +by a prior UnsetAttributes call), pPriv->events is NULL, and | ||
| 15 | +pPriv->installedMap is None, then CheckScreenPrivate determines the screen | ||
| 16 | +private is unused, frees it, and sets the screen private pointer to NULL. | ||
| 17 | + | ||
| 18 | +The function then continues to dereference the now-freed pPriv on the very | ||
| 19 | +next line (pPriv->attr), resulting in a use-after-free. On glibc 2.34+, | ||
| 20 | +the tcache key at offset 8 within the freed block makes pPriv->attr appear | ||
| 21 | +non-NULL, causing the function to continue operating on garbage data and | ||
| 22 | +eventually crash. | ||
| 23 | + | ||
| 24 | +The attack sequence is: | ||
| 25 | + 1. SetAttributes (creates pPriv with pPriv->attr set) | ||
| 26 | + 2. ForceScreenSaver(Active) (creates saver window, pPriv->hasWindow=TRUE) | ||
| 27 | + 3. UnsetAttributes (sets pPriv->attr = NULL) | ||
| 28 | + 4. ForceScreenSaver(Active) (re-enters CreateSaverWindow → UAF) | ||
| 29 | + | ||
| 30 | +Fix by re-fetching pPriv from the screen private after CheckScreenPrivate | ||
| 31 | +returns, so the subsequent NULL check correctly detects the freed state. | ||
| 32 | + | ||
| 33 | +ScreenSaverFreeAttr has the same pattern, force pPriv to NULL there too | ||
| 34 | +even though it has no real effect. | ||
| 35 | + | ||
| 36 | +This vulnerability was discovered by: | ||
| 37 | +Anonymous working with TrendAI Zero Day Initiative | ||
| 38 | + | ||
| 39 | +ZDI-CAN-30168 | ||
| 40 | + | ||
| 41 | +Assisted-by: Claude:claude-opus-4-6 | ||
| 42 | +(cherry picked from commit ecc634f1b2f7aa473d3a267eada98c4918bf9e05) | ||
| 43 | + | ||
| 44 | +Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2229> | ||
| 45 | + | ||
| 46 | +Reference:https://gitlab.freedesktop.org/xorg/xserver/-/commit/182c23f780402062ab31963776a19d5b87e25ac8 | ||
| 47 | +Conflict:no | ||
| 48 | +--- | ||
| 49 | + Xext/saver.c | 5 +++++ | ||
| 50 | + 1 file changed, 5 insertions(+) | ||
| 51 | + | ||
| 52 | +diff --git a/Xext/saver.c b/Xext/saver.c | ||
| 53 | +index fd6153c31..0780e80ab 100644 | ||
| 54 | +--- a/Xext/saver.c | ||
| 55 | ++++ b/Xext/saver.c | ||
| 56 | + ScreenSaverFreeAttr(void *value, XID id) | ||
| 57 | + dixSaveScreens(serverClient, SCREEN_SAVER_FORCER, ScreenSaverActive); | ||
| 58 | + } | ||
| 59 | + CheckScreenPrivate(pScreen); | ||
| 60 | ++ /* CheckScreenPrivate may have freed pPriv (same pattern as | ||
| 61 | ++ * CreateSaverWindow fix for ZDI-CAN-30168). */ | ||
| 62 | ++ pPriv = NULL; | ||
| 63 | + return TRUE; | ||
| 64 | + } | ||
| 65 | + | ||
| 66 | + CreateSaverWindow(ScreenPtr pScreen) | ||
| 67 | + UninstallSaverColormap(pScreen); | ||
| 68 | + pPriv->hasWindow = FALSE; | ||
| 69 | + CheckScreenPrivate(pScreen); | ||
| 70 | ++ /* Re-fetch pPriv since CheckScreenPrivate may have freed it */ | ||
| 71 | ++ pPriv = GetScreenPrivate(pScreen); | ||
| 72 | + } | ||
| 73 | + } | ||
| 74 | + | ||
| 75 | +-- | ||
| 76 | +2.33.0 | ||
| 77 | + | ||
| @@ -16,7 +16,7 @@ | |||
| 16 | 16 | ||
| 17 | Name: xorg-x11-server | 17 | Name: xorg-x11-server |
| 18 | Version: 1.20.8 | 18 | Version: 1.20.8 |
| 19 | -Release: 37 | 19 | +Release: 38 |
| 20 | Summary: X.Org X11 X server | 20 | Summary: X.Org X11 X server |
| 21 | License: MIT and GPLv2 | 21 | License: MIT and GPLv2 |
| 22 | URL: https://www.x.org | 22 | URL: https://www.x.org |
| @@ -160,6 +160,15 @@ Patch6072: backport-CVE-2026-34001.patch | |||
| 160 | Patch6073: backport-CVE-2026-34002.patch | 160 | Patch6073: backport-CVE-2026-34002.patch |
| 161 | Patch6074: backport-0001-CVE-2026-34003.patch | 161 | Patch6074: backport-0001-CVE-2026-34003.patch |
| 162 | Patch6075: backport-0002-CVE-2026-34003.patch | 162 | Patch6075: backport-0002-CVE-2026-34003.patch |
| 163 | +Patch6076: backport-CVE-2026-50256.patch | ||
| 164 | +Patch6077: backport-CVE-2026-50257-CVE-2026-50260.patch | ||
| 165 | +Patch6078: backport-CVE-2026-50258.patch | ||
| 166 | +Patch6079: backport-CVE-2026-50259.patch | ||
| 167 | +Patch6080: backport-CVE-2026-50261.patch | ||
| 168 | +Patch6081: backport-CVE-2026-50262.patch | ||
| 169 | +Patch6082: backport-CVE-2026-50263.patch | ||
| 170 | +Patch6083: backport-0001-CVE-2026-50264.patch | ||
| 171 | +Patch6084: backport-0002-CVE-2026-50264.patch | ||
| 163 | 172 | ||
| 164 | BuildRequires: audit-libs-devel autoconf automake bison dbus-devel flex flex-devel git gcc | 173 | BuildRequires: audit-libs-devel autoconf automake bison dbus-devel flex flex-devel git gcc |
| 165 | BuildRequires: systemtap-sdt-devel libtool pkgconfig | 174 | BuildRequires: systemtap-sdt-devel libtool pkgconfig |
| @@ -403,6 +412,9 @@ find %{inst_srcdir}/hw/xfree86 -name \*.c -delete | |||
| 403 | %{_libdir}/xorg/protocol.txt | 412 | %{_libdir}/xorg/protocol.txt |
| 404 | 413 | ||
| 405 | %changelog | 414 | %changelog |
| 415 | +* Mon Jun 08 2026 lingsheng <ultra_planet@qq.com> - 1.20.8-38 | ||
| 416 | +- fix CVE-2026-50256 CVE-2026-50257 CVE-2026-50258 CVE-2026-50259 CVE-2026-50260 CVE-2026-50261 CVE-2026-50262 CVE-2026-50263 CVE-2026-50264 | ||
| 417 | + | ||
| 406 | * Fri Apr 24 2026 lingsheng <ultra_planet@qq.com> - 1.20.8-37 | 418 | * Fri Apr 24 2026 lingsheng <ultra_planet@qq.com> - 1.20.8-37 |
| 407 | - fix CVE-2026-33999 CVE-2026-34000 CVE-2026-34001 CVE-2026-34002 CVE-2026-34003 | 419 | - fix CVE-2026-33999 CVE-2026-34000 CVE-2026-34001 CVE-2026-34002 CVE-2026-34003 |
| 408 | 420 | ||