Toshaan Bharvani
5 months ago
16 changed files with 1082 additions and 1 deletions
@ -0,0 +1,36 @@ |
|||||||
|
From 9ca7d3f61a88ae6cf47fdf139b6215d745db976b Mon Sep 17 00:00:00 2001 |
||||||
|
From: Peter Hutterer <peter.hutterer@who-t.net> |
||||||
|
Date: Wed, 25 Jan 2023 11:41:40 +1000 |
||||||
|
Subject: [PATCH xserver] Xi: fix potential use-after-free in |
||||||
|
DeepCopyPointerClasses |
||||||
|
|
||||||
|
CVE-2023-0494, ZDI-CAN-19596 |
||||||
|
|
||||||
|
This vulnerability was discovered by: |
||||||
|
Jan-Niklas Sohn working with Trend Micro Zero Day Initiative |
||||||
|
|
||||||
|
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> |
||||||
|
(cherry picked from commit 0ba6d8c37071131a49790243cdac55392ecf71ec) |
||||||
|
--- |
||||||
|
Xi/exevents.c | 4 +++- |
||||||
|
1 file changed, 3 insertions(+), 1 deletion(-) |
||||||
|
|
||||||
|
diff --git a/Xi/exevents.c b/Xi/exevents.c |
||||||
|
index 217baa9561..dcd4efb3bc 100644 |
||||||
|
--- a/Xi/exevents.c |
||||||
|
+++ b/Xi/exevents.c |
||||||
|
@@ -619,8 +619,10 @@ DeepCopyPointerClasses(DeviceIntPtr from, DeviceIntPtr to) |
||||||
|
memcpy(to->button->xkb_acts, from->button->xkb_acts, |
||||||
|
sizeof(XkbAction)); |
||||||
|
} |
||||||
|
- else |
||||||
|
+ else { |
||||||
|
free(to->button->xkb_acts); |
||||||
|
+ to->button->xkb_acts = NULL; |
||||||
|
+ } |
||||||
|
|
||||||
|
memcpy(to->button->labels, from->button->labels, |
||||||
|
from->button->numButtons * sizeof(Atom)); |
||||||
|
-- |
||||||
|
2.39.0 |
||||||
|
|
@ -0,0 +1,52 @@ |
|||||||
|
From b320ca0ffe4c0c872eeb3a93d9bde21f765c7c63 Mon Sep 17 00:00:00 2001 |
||||||
|
From: Peter Hutterer <peter.hutterer@who-t.net> |
||||||
|
Date: Tue, 29 Nov 2022 12:55:45 +1000 |
||||||
|
Subject: [PATCH xserver 1/7] Xtest: disallow GenericEvents in |
||||||
|
XTestSwapFakeInput |
||||||
|
|
||||||
|
XTestSwapFakeInput assumes all events in this request are |
||||||
|
sizeof(xEvent) and iterates through these in 32-byte increments. |
||||||
|
However, a GenericEvent may be of arbitrary length longer than 32 bytes, |
||||||
|
so any GenericEvent in this list would result in subsequent events to be |
||||||
|
misparsed. |
||||||
|
|
||||||
|
Additional, the swapped event is written into a stack-allocated struct |
||||||
|
xEvent (size 32 bytes). For any GenericEvent longer than 32 bytes, |
||||||
|
swapping the event may thus smash the stack like an avocado on toast. |
||||||
|
|
||||||
|
Catch this case early and return BadValue for any GenericEvent. |
||||||
|
Which is what would happen in unswapped setups anyway since XTest |
||||||
|
doesn't support GenericEvent. |
||||||
|
|
||||||
|
CVE-2022-46340, ZDI-CAN 19265 |
||||||
|
|
||||||
|
This vulnerability was discovered by: |
||||||
|
Jan-Niklas Sohn working with Trend Micro Zero Day Initiative |
||||||
|
|
||||||
|
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> |
||||||
|
Acked-by: Olivier Fourdan <ofourdan@redhat.com> |
||||||
|
--- |
||||||
|
Xext/xtest.c | 5 +++-- |
||||||
|
1 file changed, 3 insertions(+), 2 deletions(-) |
||||||
|
|
||||||
|
diff --git a/Xext/xtest.c b/Xext/xtest.c |
||||||
|
index bf27eb590b..2985a4ce6e 100644 |
||||||
|
--- a/Xext/xtest.c |
||||||
|
+++ b/Xext/xtest.c |
||||||
|
@@ -502,10 +502,11 @@ XTestSwapFakeInput(ClientPtr client, xReq * req) |
||||||
|
|
||||||
|
nev = ((req->length << 2) - sizeof(xReq)) / sizeof(xEvent); |
||||||
|
for (ev = (xEvent *) &req[1]; --nev >= 0; ev++) { |
||||||
|
+ int evtype = ev->u.u.type & 0x177; |
||||||
|
/* Swap event */ |
||||||
|
- proc = EventSwapVector[ev->u.u.type & 0177]; |
||||||
|
+ proc = EventSwapVector[evtype]; |
||||||
|
/* no swapping proc; invalid event type? */ |
||||||
|
- if (!proc || proc == NotImplemented) { |
||||||
|
+ if (!proc || proc == NotImplemented || evtype == GenericEvent) { |
||||||
|
client->errorValue = ev->u.u.type; |
||||||
|
return BadValue; |
||||||
|
} |
||||||
|
-- |
||||||
|
2.38.1 |
||||||
|
|
@ -0,0 +1,72 @@ |
|||||||
|
From e67e988730346c63d2f0cdf2531ed36b0c7ad5a6 Mon Sep 17 00:00:00 2001 |
||||||
|
From: Peter Hutterer <peter.hutterer@who-t.net> |
||||||
|
Date: Wed, 23 Nov 2022 14:50:29 +1000 |
||||||
|
Subject: [PATCH xserver] configure.ac: search for the fontrootdir ourselves |
||||||
|
|
||||||
|
This replaces the use of font-utils' .m4 macro set with a copy of the |
||||||
|
only one we actually want: the bit for the fontrootpath. |
||||||
|
|
||||||
|
We don't need configure options for every single subfont directory, so |
||||||
|
let's hardcode those in the default font path. Like meson does upstream |
||||||
|
too. |
||||||
|
|
||||||
|
With this patch we no longer require the font-utils dependency. |
||||||
|
|
||||||
|
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> |
||||||
|
--- |
||||||
|
configure.ac | 28 +++++++++++++++++----------- |
||||||
|
1 file changed, 17 insertions(+), 11 deletions(-) |
||||||
|
|
||||||
|
diff --git a/configure.ac b/configure.ac |
||||||
|
index 0909cc5b4d..2349320888 100644 |
||||||
|
--- a/configure.ac |
||||||
|
+++ b/configure.ac |
||||||
|
@@ -49,9 +49,6 @@ XORG_WITH_XSLTPROC |
||||||
|
XORG_ENABLE_UNIT_TESTS |
||||||
|
XORG_LD_WRAP([optional]) |
||||||
|
|
||||||
|
-m4_ifndef([XORG_FONT_MACROS_VERSION], [m4_fatal([must install font-util 1.1 or later before running autoconf/autogen])]) |
||||||
|
-XORG_FONT_MACROS_VERSION(1.1) |
||||||
|
- |
||||||
|
dnl this gets generated by autoheader, and thus contains all the defines. we |
||||||
|
dnl don't ever actually use it, internally. |
||||||
|
AC_CONFIG_HEADERS(include/do-not-use-config.h) |
||||||
|
@@ -450,18 +447,27 @@ AC_MSG_RESULT([$FALLBACK_INPUT_DRIVER]) |
||||||
|
AC_DEFINE_UNQUOTED(FALLBACK_INPUT_DRIVER, ["$FALLBACK_INPUT_DRIVER"], [ Fallback input driver ]) |
||||||
|
|
||||||
|
dnl Determine font path |
||||||
|
-XORG_FONTROOTDIR |
||||||
|
-XORG_FONTSUBDIR(FONTMISCDIR, fontmiscdir, misc) |
||||||
|
-XORG_FONTSUBDIR(FONTOTFDIR, fontotfdir, OTF) |
||||||
|
-XORG_FONTSUBDIR(FONTTTFDIR, fontttfdir, TTF) |
||||||
|
-XORG_FONTSUBDIR(FONTTYPE1DIR, fonttype1dir, Type1) |
||||||
|
-XORG_FONTSUBDIR(FONT75DPIDIR, font75dpidir, 75dpi) |
||||||
|
-XORG_FONTSUBDIR(FONT100DPIDIR, font100dpidir, 100dpi) |
||||||
|
+dnl This is a copy of XORG_FONTROOTDIR from font-utils so we can drop the dependency |
||||||
|
+AC_MSG_CHECKING([for root directory for font files]) |
||||||
|
+AC_ARG_WITH(fontrootdir, |
||||||
|
+ AS_HELP_STRING([--with-fontrootdir=DIR], |
||||||
|
+ [Path to root directory for font files]), |
||||||
|
+ [FONTROOTDIR="$withval"]) |
||||||
|
+# if --with-fontrootdir not specified... |
||||||
|
+if test "x${FONTROOTDIR}" = "x"; then |
||||||
|
+ FONTROOTDIR=`$PKG_CONFIG --variable=fontrootdir fontutil` |
||||||
|
+fi |
||||||
|
+# ...and if pkg-config didn't find fontdir in fontutil.pc... |
||||||
|
+if test "x${FONTROOTDIR}" = "x"; then |
||||||
|
+ FONTROOTDIR="${datadir}/fonts/X11" |
||||||
|
+fi |
||||||
|
+AC_SUBST(FONTROOTDIR) |
||||||
|
+AC_MSG_RESULT([${FONTROOTDIR}]) |
||||||
|
|
||||||
|
dnl Uses --with-default-font-path if set, otherwise uses standard |
||||||
|
dnl subdirectories of FONTROOTDIR. Some distros set the default font path to |
||||||
|
dnl "catalogue:/etc/X11/fontpath.d,built-ins" |
||||||
|
-DEFAULT_FONT_PATH="${FONTMISCDIR}/,${FONTTTFDIR}/,${FONTOTFDIR}/,${FONTTYPE1DIR}/,${FONT100DPIDIR}/,${FONT75DPIDIR}/" |
||||||
|
+DEFAULT_FONT_PATH="${FONTROOTDIR}/misc,${FONTROOTDIR}/OTF,${FONTROOTDIR}/TTF,${FONTROOTDIR}/Type1,${FONTROOTDIR}/75dpi,${FONTROOTDIR}/100dpi" |
||||||
|
case $host_os in |
||||||
|
darwin*) DEFAULT_FONT_PATH="${DEFAULT_FONT_PATH},/Library/Fonts,/System/Library/Fonts" ;; |
||||||
|
esac |
||||||
|
-- |
||||||
|
2.38.1 |
||||||
|
|
@ -0,0 +1,59 @@ |
|||||||
|
From 18f91b950e22c2a342a4fbc55e9ddf7534a707d2 Mon Sep 17 00:00:00 2001 |
||||||
|
From: Peter Hutterer <peter.hutterer@who-t.net> |
||||||
|
Date: Wed, 13 Jul 2022 11:23:09 +1000 |
||||||
|
Subject: [PATCH xserver] xkb: fix some possible memleaks in XkbGetKbdByName |
||||||
|
|
||||||
|
GetComponentByName returns an allocated string, so let's free that if we |
||||||
|
fail somewhere. |
||||||
|
|
||||||
|
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> |
||||||
|
--- |
||||||
|
xkb/xkb.c | 26 ++++++++++++++++++++------ |
||||||
|
1 file changed, 20 insertions(+), 6 deletions(-) |
||||||
|
|
||||||
|
diff --git a/xkb/xkb.c b/xkb/xkb.c |
||||||
|
index 4692895db..b79a269e3 100644 |
||||||
|
--- a/xkb/xkb.c |
||||||
|
+++ b/xkb/xkb.c |
||||||
|
@@ -5935,18 +5935,32 @@ ProcXkbGetKbdByName(ClientPtr client) |
||||||
|
xkb = dev->key->xkbInfo->desc; |
||||||
|
status = Success; |
||||||
|
str = (unsigned char *) &stuff[1]; |
||||||
|
- if (GetComponentSpec(&str, TRUE, &status)) /* keymap, unsupported */ |
||||||
|
- return BadMatch; |
||||||
|
+ { |
||||||
|
+ char *keymap = GetComponentSpec(&str, TRUE, &status); /* keymap, unsupported */ |
||||||
|
+ if (keymap) { |
||||||
|
+ free(keymap); |
||||||
|
+ return BadMatch; |
||||||
|
+ } |
||||||
|
+ } |
||||||
|
names.keycodes = GetComponentSpec(&str, TRUE, &status); |
||||||
|
names.types = GetComponentSpec(&str, TRUE, &status); |
||||||
|
names.compat = GetComponentSpec(&str, TRUE, &status); |
||||||
|
names.symbols = GetComponentSpec(&str, TRUE, &status); |
||||||
|
names.geometry = GetComponentSpec(&str, TRUE, &status); |
||||||
|
- if (status != Success) |
||||||
|
+ if (status == Success) { |
||||||
|
+ len = str - ((unsigned char *) stuff); |
||||||
|
+ if ((XkbPaddedSize(len) / 4) != stuff->length) |
||||||
|
+ status = BadLength; |
||||||
|
+ } |
||||||
|
+ |
||||||
|
+ if (status != Success) { |
||||||
|
+ free(names.keycodes); |
||||||
|
+ free(names.types); |
||||||
|
+ free(names.compat); |
||||||
|
+ free(names.symbols); |
||||||
|
+ free(names.geometry); |
||||||
|
return status; |
||||||
|
- len = str - ((unsigned char *) stuff); |
||||||
|
- if ((XkbPaddedSize(len) / 4) != stuff->length) |
||||||
|
- return BadLength; |
||||||
|
+ } |
||||||
|
|
||||||
|
CHK_MASK_LEGAL(0x01, stuff->want, XkbGBN_AllComponentsMask); |
||||||
|
CHK_MASK_LEGAL(0x02, stuff->need, XkbGBN_AllComponentsMask); |
||||||
|
-- |
||||||
|
2.38.1 |
||||||
|
|
@ -0,0 +1,35 @@ |
|||||||
|
From 11beef0b7f1ed290348e45618e5fa0d2bffcb72e Mon Sep 17 00:00:00 2001 |
||||||
|
From: Peter Hutterer <peter.hutterer@who-t.net> |
||||||
|
Date: Tue, 5 Jul 2022 12:06:20 +1000 |
||||||
|
Subject: [PATCH xserver] xkb: proof GetCountedString against request length |
||||||
|
attacks |
||||||
|
|
||||||
|
GetCountedString did a check for the whole string to be within the |
||||||
|
request buffer but not for the initial 2 bytes that contain the length |
||||||
|
field. A swapped client could send a malformed request to trigger a |
||||||
|
swaps() on those bytes, writing into random memory. |
||||||
|
|
||||||
|
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> |
||||||
|
--- |
||||||
|
xkb/xkb.c | 5 +++++ |
||||||
|
1 file changed, 5 insertions(+) |
||||||
|
|
||||||
|
diff --git a/xkb/xkb.c b/xkb/xkb.c |
||||||
|
index f42f59ef3..1841cff26 100644 |
||||||
|
--- a/xkb/xkb.c |
||||||
|
+++ b/xkb/xkb.c |
||||||
|
@@ -5137,6 +5137,11 @@ _GetCountedString(char **wire_inout, ClientPtr client, char **str) |
||||||
|
CARD16 len; |
||||||
|
|
||||||
|
wire = *wire_inout; |
||||||
|
+ |
||||||
|
+ if (client->req_len < |
||||||
|
+ bytes_to_int32(wire + 2 - (char *) client->requestBuffer)) |
||||||
|
+ return BadValue; |
||||||
|
+ |
||||||
|
len = *(CARD16 *) wire; |
||||||
|
if (client->swapped) { |
||||||
|
swaps(&len); |
||||||
|
-- |
||||||
|
2.38.1 |
||||||
|
|
@ -0,0 +1,77 @@ |
|||||||
|
From c9b379ec5a1a34692af06056925bd0fc5f809713 Mon Sep 17 00:00:00 2001 |
||||||
|
From: Peter Hutterer <peter.hutterer@who-t.net> |
||||||
|
Date: Tue, 5 Jul 2022 12:40:47 +1000 |
||||||
|
Subject: [PATCH xserver 1/3] xkb: switch to array index loops to moving |
||||||
|
pointers |
||||||
|
|
||||||
|
Most similar loops here use a pointer that advances with each loop |
||||||
|
iteration, let's do the same here for consistency. |
||||||
|
|
||||||
|
No functional changes. |
||||||
|
|
||||||
|
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> |
||||||
|
Reviewed-by: Olivier Fourdan <ofourdan@redhat.com> |
||||||
|
(cherry picked from commit f1070c01d616c5f21f939d5ebc533738779451ac) |
||||||
|
--- |
||||||
|
xkb/xkb.c | 20 ++++++++++---------- |
||||||
|
1 file changed, 10 insertions(+), 10 deletions(-) |
||||||
|
|
||||||
|
diff --git a/xkb/xkb.c b/xkb/xkb.c |
||||||
|
index d056c698c..684394d77 100644 |
||||||
|
--- a/xkb/xkb.c |
||||||
|
+++ b/xkb/xkb.c |
||||||
|
@@ -5372,16 +5372,16 @@ _CheckSetSections(XkbGeometryPtr geom, |
||||||
|
row->left = rWire->left; |
||||||
|
row->vertical = rWire->vertical; |
||||||
|
kWire = (xkbKeyWireDesc *) &rWire[1]; |
||||||
|
- for (k = 0; k < rWire->nKeys; k++) { |
||||||
|
+ for (k = 0; k < rWire->nKeys; k++, kWire++) { |
||||||
|
XkbKeyPtr key; |
||||||
|
|
||||||
|
key = XkbAddGeomKey(row); |
||||||
|
if (!key) |
||||||
|
return BadAlloc; |
||||||
|
- memcpy(key->name.name, kWire[k].name, XkbKeyNameLength); |
||||||
|
- key->gap = kWire[k].gap; |
||||||
|
- key->shape_ndx = kWire[k].shapeNdx; |
||||||
|
- key->color_ndx = kWire[k].colorNdx; |
||||||
|
+ memcpy(key->name.name, kWire->name, XkbKeyNameLength); |
||||||
|
+ key->gap = kWire->gap; |
||||||
|
+ key->shape_ndx = kWire->shapeNdx; |
||||||
|
+ key->color_ndx = kWire->colorNdx; |
||||||
|
if (key->shape_ndx >= geom->num_shapes) { |
||||||
|
client->errorValue = _XkbErrCode3(0x10, key->shape_ndx, |
||||||
|
geom->num_shapes); |
||||||
|
@@ -5393,7 +5393,7 @@ _CheckSetSections(XkbGeometryPtr geom, |
||||||
|
return BadMatch; |
||||||
|
} |
||||||
|
} |
||||||
|
- rWire = (xkbRowWireDesc *) &kWire[rWire->nKeys]; |
||||||
|
+ rWire = (xkbRowWireDesc *)kWire; |
||||||
|
} |
||||||
|
wire = (char *) rWire; |
||||||
|
if (sWire->nDoodads > 0) { |
||||||
|
@@ -5458,16 +5458,16 @@ _CheckSetShapes(XkbGeometryPtr geom, |
||||||
|
return BadAlloc; |
||||||
|
ol->corner_radius = olWire->cornerRadius; |
||||||
|
ptWire = (xkbPointWireDesc *) &olWire[1]; |
||||||
|
- for (p = 0, pt = ol->points; p < olWire->nPoints; p++, pt++) { |
||||||
|
- pt->x = ptWire[p].x; |
||||||
|
- pt->y = ptWire[p].y; |
||||||
|
+ for (p = 0, pt = ol->points; p < olWire->nPoints; p++, pt++, ptWire++) { |
||||||
|
+ pt->x = ptWire->x; |
||||||
|
+ pt->y = ptWire->y; |
||||||
|
if (client->swapped) { |
||||||
|
swaps(&pt->x); |
||||||
|
swaps(&pt->y); |
||||||
|
} |
||||||
|
} |
||||||
|
ol->num_points = olWire->nPoints; |
||||||
|
- olWire = (xkbOutlineWireDesc *) (&ptWire[olWire->nPoints]); |
||||||
|
+ olWire = (xkbOutlineWireDesc *)ptWire; |
||||||
|
} |
||||||
|
if (shapeWire->primaryNdx != XkbNoShape) |
||||||
|
shape->primary = &shape->outlines[shapeWire->primaryNdx]; |
||||||
|
-- |
||||||
|
2.36.1 |
||||||
|
|
@ -0,0 +1,41 @@ |
|||||||
|
From cb260ba95d2bb1ae98b05e289d1b7947ac409230 Mon Sep 17 00:00:00 2001 |
||||||
|
From: Peter Hutterer <peter.hutterer@who-t.net> |
||||||
|
Date: Tue, 29 Nov 2022 13:24:00 +1000 |
||||||
|
Subject: [PATCH xserver 2/7] Xi: return an error from XI property changes if |
||||||
|
verification failed |
||||||
|
|
||||||
|
Both ProcXChangeDeviceProperty and ProcXIChangeProperty checked the |
||||||
|
property for validity but didn't actually return the potential error. |
||||||
|
|
||||||
|
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> |
||||||
|
Acked-by: Olivier Fourdan <ofourdan@redhat.com> |
||||||
|
--- |
||||||
|
Xi/xiproperty.c | 5 +++++ |
||||||
|
1 file changed, 5 insertions(+) |
||||||
|
|
||||||
|
diff --git a/Xi/xiproperty.c b/Xi/xiproperty.c |
||||||
|
index a36f7d61df..68c362c628 100644 |
||||||
|
--- a/Xi/xiproperty.c |
||||||
|
+++ b/Xi/xiproperty.c |
||||||
|
@@ -902,6 +902,8 @@ ProcXChangeDeviceProperty(ClientPtr client) |
||||||
|
|
||||||
|
rc = check_change_property(client, stuff->property, stuff->type, |
||||||
|
stuff->format, stuff->mode, stuff->nUnits); |
||||||
|
+ if (rc != Success) |
||||||
|
+ return rc; |
||||||
|
|
||||||
|
len = stuff->nUnits; |
||||||
|
if (len > (bytes_to_int32(0xffffffff - sizeof(xChangeDevicePropertyReq)))) |
||||||
|
@@ -1141,6 +1143,9 @@ ProcXIChangeProperty(ClientPtr client) |
||||||
|
|
||||||
|
rc = check_change_property(client, stuff->property, stuff->type, |
||||||
|
stuff->format, stuff->mode, stuff->num_items); |
||||||
|
+ if (rc != Success) |
||||||
|
+ return rc; |
||||||
|
+ |
||||||
|
len = stuff->num_items; |
||||||
|
if (len > bytes_to_int32(0xffffffff - sizeof(xXIChangePropertyReq))) |
||||||
|
return BadLength; |
||||||
|
-- |
||||||
|
2.38.1 |
||||||
|
|
@ -0,0 +1,180 @@ |
|||||||
|
From 45a0af83129eb7dc244c5118360afc1972a686c7 Mon Sep 17 00:00:00 2001 |
||||||
|
From: Peter Hutterer <peter.hutterer@who-t.net> |
||||||
|
Date: Tue, 5 Jul 2022 09:50:41 +1000 |
||||||
|
Subject: [PATCH xserver 2/3] xkb: swap XkbSetDeviceInfo and |
||||||
|
XkbSetDeviceInfoCheck |
||||||
|
|
||||||
|
XKB often uses a FooCheck and Foo function pair, the former is supposed |
||||||
|
to check all values in the request and error out on BadLength, |
||||||
|
BadValue, etc. The latter is then called once we're confident the values |
||||||
|
are good (they may still fail on an individual device, but that's a |
||||||
|
different topic). |
||||||
|
|
||||||
|
In the case of XkbSetDeviceInfo, those functions were incorrectly |
||||||
|
named, with XkbSetDeviceInfo ending up as the checker function and |
||||||
|
XkbSetDeviceInfoCheck as the setter function. As a result, the setter |
||||||
|
function was called before the checker function, accessing request |
||||||
|
data and modifying device state before we ensured that the data is |
||||||
|
valid. |
||||||
|
|
||||||
|
In particular, the setter function relied on values being already |
||||||
|
byte-swapped. This in turn could lead to potential OOB memory access. |
||||||
|
|
||||||
|
Fix this by correctly naming the functions and moving the length checks |
||||||
|
over to the checker function. These were added in 87c64fc5b0 to the |
||||||
|
wrong function, probably due to the incorrect naming. |
||||||
|
|
||||||
|
Fixes ZDI-CAN 16070, CVE-2022-2320. |
||||||
|
|
||||||
|
This vulnerability was discovered by: |
||||||
|
Jan-Niklas Sohn working with Trend Micro Zero Day Initiative |
||||||
|
|
||||||
|
Introduced in c06e27b2f6fd9f7b9f827623a48876a225264132 |
||||||
|
|
||||||
|
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> |
||||||
|
(cherry picked from commit dd8caf39e9e15d8f302e54045dd08d8ebf1025dc) |
||||||
|
--- |
||||||
|
xkb/xkb.c | 46 +++++++++++++++++++++++++--------------------- |
||||||
|
1 file changed, 25 insertions(+), 21 deletions(-) |
||||||
|
|
||||||
|
diff --git a/xkb/xkb.c b/xkb/xkb.c |
||||||
|
index 684394d77..36464a770 100644 |
||||||
|
--- a/xkb/xkb.c |
||||||
|
+++ b/xkb/xkb.c |
||||||
|
@@ -6554,7 +6554,8 @@ ProcXkbGetDeviceInfo(ClientPtr client) |
||||||
|
static char * |
||||||
|
CheckSetDeviceIndicators(char *wire, |
||||||
|
DeviceIntPtr dev, |
||||||
|
- int num, int *status_rtrn, ClientPtr client) |
||||||
|
+ int num, int *status_rtrn, ClientPtr client, |
||||||
|
+ xkbSetDeviceInfoReq * stuff) |
||||||
|
{ |
||||||
|
xkbDeviceLedsWireDesc *ledWire; |
||||||
|
int i; |
||||||
|
@@ -6562,6 +6563,11 @@ CheckSetDeviceIndicators(char *wire, |
||||||
|
|
||||||
|
ledWire = (xkbDeviceLedsWireDesc *) wire; |
||||||
|
for (i = 0; i < num; i++) { |
||||||
|
+ if (!_XkbCheckRequestBounds(client, stuff, ledWire, ledWire + 1)) { |
||||||
|
+ *status_rtrn = BadLength; |
||||||
|
+ return (char *) ledWire; |
||||||
|
+ } |
||||||
|
+ |
||||||
|
if (client->swapped) { |
||||||
|
swaps(&ledWire->ledClass); |
||||||
|
swaps(&ledWire->ledID); |
||||||
|
@@ -6589,6 +6595,11 @@ CheckSetDeviceIndicators(char *wire, |
||||||
|
atomWire = (CARD32 *) &ledWire[1]; |
||||||
|
if (nNames > 0) { |
||||||
|
for (n = 0; n < nNames; n++) { |
||||||
|
+ if (!_XkbCheckRequestBounds(client, stuff, atomWire, atomWire + 1)) { |
||||||
|
+ *status_rtrn = BadLength; |
||||||
|
+ return (char *) atomWire; |
||||||
|
+ } |
||||||
|
+ |
||||||
|
if (client->swapped) { |
||||||
|
swapl(atomWire); |
||||||
|
} |
||||||
|
@@ -6600,6 +6611,10 @@ CheckSetDeviceIndicators(char *wire, |
||||||
|
mapWire = (xkbIndicatorMapWireDesc *) atomWire; |
||||||
|
if (nMaps > 0) { |
||||||
|
for (n = 0; n < nMaps; n++) { |
||||||
|
+ if (!_XkbCheckRequestBounds(client, stuff, mapWire, mapWire + 1)) { |
||||||
|
+ *status_rtrn = BadLength; |
||||||
|
+ return (char *) mapWire; |
||||||
|
+ } |
||||||
|
if (client->swapped) { |
||||||
|
swaps(&mapWire->virtualMods); |
||||||
|
swapl(&mapWire->ctrls); |
||||||
|
@@ -6651,11 +6666,6 @@ SetDeviceIndicators(char *wire, |
||||||
|
xkbIndicatorMapWireDesc *mapWire; |
||||||
|
XkbSrvLedInfoPtr sli; |
||||||
|
|
||||||
|
- if (!_XkbCheckRequestBounds(client, stuff, ledWire, ledWire + 1)) { |
||||||
|
- *status_rtrn = BadLength; |
||||||
|
- return (char *) ledWire; |
||||||
|
- } |
||||||
|
- |
||||||
|
namec = mapc = statec = 0; |
||||||
|
sli = XkbFindSrvLedInfo(dev, ledWire->ledClass, ledWire->ledID, |
||||||
|
XkbXI_IndicatorMapsMask); |
||||||
|
@@ -6674,10 +6684,6 @@ SetDeviceIndicators(char *wire, |
||||||
|
memset((char *) sli->names, 0, XkbNumIndicators * sizeof(Atom)); |
||||||
|
for (n = 0, bit = 1; n < XkbNumIndicators; n++, bit <<= 1) { |
||||||
|
if (ledWire->namesPresent & bit) { |
||||||
|
- if (!_XkbCheckRequestBounds(client, stuff, atomWire, atomWire + 1)) { |
||||||
|
- *status_rtrn = BadLength; |
||||||
|
- return (char *) atomWire; |
||||||
|
- } |
||||||
|
sli->names[n] = (Atom) *atomWire; |
||||||
|
if (sli->names[n] == None) |
||||||
|
ledWire->namesPresent &= ~bit; |
||||||
|
@@ -6695,10 +6701,6 @@ SetDeviceIndicators(char *wire, |
||||||
|
if (ledWire->mapsPresent) { |
||||||
|
for (n = 0, bit = 1; n < XkbNumIndicators; n++, bit <<= 1) { |
||||||
|
if (ledWire->mapsPresent & bit) { |
||||||
|
- if (!_XkbCheckRequestBounds(client, stuff, mapWire, mapWire + 1)) { |
||||||
|
- *status_rtrn = BadLength; |
||||||
|
- return (char *) mapWire; |
||||||
|
- } |
||||||
|
sli->maps[n].flags = mapWire->flags; |
||||||
|
sli->maps[n].which_groups = mapWire->whichGroups; |
||||||
|
sli->maps[n].groups = mapWire->groups; |
||||||
|
@@ -6734,13 +6736,17 @@ SetDeviceIndicators(char *wire, |
||||||
|
} |
||||||
|
|
||||||
|
static int |
||||||
|
-_XkbSetDeviceInfo(ClientPtr client, DeviceIntPtr dev, |
||||||
|
+_XkbSetDeviceInfoCheck(ClientPtr client, DeviceIntPtr dev, |
||||||
|
xkbSetDeviceInfoReq * stuff) |
||||||
|
{ |
||||||
|
char *wire; |
||||||
|
|
||||||
|
wire = (char *) &stuff[1]; |
||||||
|
if (stuff->change & XkbXI_ButtonActionsMask) { |
||||||
|
+ int sz = stuff->nBtns * SIZEOF(xkbActionWireDesc); |
||||||
|
+ if (!_XkbCheckRequestBounds(client, stuff, wire, (char *) wire + sz)) |
||||||
|
+ return BadLength; |
||||||
|
+ |
||||||
|
if (!dev->button) { |
||||||
|
client->errorValue = _XkbErrCode2(XkbErr_BadClass, ButtonClass); |
||||||
|
return XkbKeyboardErrorCode; |
||||||
|
@@ -6751,13 +6757,13 @@ _XkbSetDeviceInfo(ClientPtr client, DeviceIntPtr dev, |
||||||
|
dev->button->numButtons); |
||||||
|
return BadMatch; |
||||||
|
} |
||||||
|
- wire += (stuff->nBtns * SIZEOF(xkbActionWireDesc)); |
||||||
|
+ wire += sz; |
||||||
|
} |
||||||
|
if (stuff->change & XkbXI_IndicatorsMask) { |
||||||
|
int status = Success; |
||||||
|
|
||||||
|
wire = CheckSetDeviceIndicators(wire, dev, stuff->nDeviceLedFBs, |
||||||
|
- &status, client); |
||||||
|
+ &status, client, stuff); |
||||||
|
if (status != Success) |
||||||
|
return status; |
||||||
|
} |
||||||
|
@@ -6768,8 +6774,8 @@ _XkbSetDeviceInfo(ClientPtr client, DeviceIntPtr dev, |
||||||
|
} |
||||||
|
|
||||||
|
static int |
||||||
|
-_XkbSetDeviceInfoCheck(ClientPtr client, DeviceIntPtr dev, |
||||||
|
- xkbSetDeviceInfoReq * stuff) |
||||||
|
+_XkbSetDeviceInfo(ClientPtr client, DeviceIntPtr dev, |
||||||
|
+ xkbSetDeviceInfoReq * stuff) |
||||||
|
{ |
||||||
|
char *wire; |
||||||
|
xkbExtensionDeviceNotify ed; |
||||||
|
@@ -6793,8 +6799,6 @@ _XkbSetDeviceInfoCheck(ClientPtr client, DeviceIntPtr dev, |
||||||
|
if (stuff->firstBtn + stuff->nBtns > nBtns) |
||||||
|
return BadValue; |
||||||
|
sz = stuff->nBtns * SIZEOF(xkbActionWireDesc); |
||||||
|
- if (!_XkbCheckRequestBounds(client, stuff, wire, (char *) wire + sz)) |
||||||
|
- return BadLength; |
||||||
|
memcpy((char *) &acts[stuff->firstBtn], (char *) wire, sz); |
||||||
|
wire += sz; |
||||||
|
ed.reason |= XkbXI_ButtonActionsMask; |
||||||
|
-- |
||||||
|
2.36.1 |
||||||
|
|
@ -0,0 +1,71 @@ |
|||||||
|
From a16f2b9693d248b81703821fd22fba8b5ba83e1a Mon Sep 17 00:00:00 2001 |
||||||
|
From: Peter Hutterer <peter.hutterer@who-t.net> |
||||||
|
Date: Tue, 29 Nov 2022 13:26:57 +1000 |
||||||
|
Subject: [PATCH xserver 3/7] Xi: avoid integer truncation in length check of |
||||||
|
ProcXIChangeProperty |
||||||
|
|
||||||
|
This fixes an OOB read and the resulting information disclosure. |
||||||
|
|
||||||
|
Length calculation for the request was clipped to a 32-bit integer. With |
||||||
|
the correct stuff->num_items value the expected request size was |
||||||
|
truncated, passing the REQUEST_FIXED_SIZE check. |
||||||
|
|
||||||
|
The server then proceeded with reading at least stuff->num_items bytes |
||||||
|
(depending on stuff->format) from the request and stuffing whatever it |
||||||
|
finds into the property. In the process it would also allocate at least |
||||||
|
stuff->num_items bytes, i.e. 4GB. |
||||||
|
|
||||||
|
The same bug exists in ProcChangeProperty and ProcXChangeDeviceProperty, |
||||||
|
so let's fix that too. |
||||||
|
|
||||||
|
CVE-2022-46344, ZDI-CAN 19405 |
||||||
|
|
||||||
|
This vulnerability was discovered by: |
||||||
|
Jan-Niklas Sohn working with Trend Micro Zero Day Initiative |
||||||
|
|
||||||
|
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> |
||||||
|
Acked-by: Olivier Fourdan <ofourdan@redhat.com> |
||||||
|
--- |
||||||
|
Xi/xiproperty.c | 4 ++-- |
||||||
|
dix/property.c | 3 ++- |
||||||
|
2 files changed, 4 insertions(+), 3 deletions(-) |
||||||
|
|
||||||
|
diff --git a/Xi/xiproperty.c b/Xi/xiproperty.c |
||||||
|
index 68c362c628..066ba21fba 100644 |
||||||
|
--- a/Xi/xiproperty.c |
||||||
|
+++ b/Xi/xiproperty.c |
||||||
|
@@ -890,7 +890,7 @@ ProcXChangeDeviceProperty(ClientPtr client) |
||||||
|
REQUEST(xChangeDevicePropertyReq); |
||||||
|
DeviceIntPtr dev; |
||||||
|
unsigned long len; |
||||||
|
- int totalSize; |
||||||
|
+ uint64_t totalSize; |
||||||
|
int rc; |
||||||
|
|
||||||
|
REQUEST_AT_LEAST_SIZE(xChangeDevicePropertyReq); |
||||||
|
@@ -1130,7 +1130,7 @@ ProcXIChangeProperty(ClientPtr client) |
||||||
|
{ |
||||||
|
int rc; |
||||||
|
DeviceIntPtr dev; |
||||||
|
- int totalSize; |
||||||
|
+ uint64_t totalSize; |
||||||
|
unsigned long len; |
||||||
|
|
||||||
|
REQUEST(xXIChangePropertyReq); |
||||||
|
diff --git a/dix/property.c b/dix/property.c |
||||||
|
index 94ef5a0ec0..acce94b2c6 100644 |
||||||
|
--- a/dix/property.c |
||||||
|
+++ b/dix/property.c |
||||||
|
@@ -205,7 +205,8 @@ ProcChangeProperty(ClientPtr client) |
||||||
|
WindowPtr pWin; |
||||||
|
char format, mode; |
||||||
|
unsigned long len; |
||||||
|
- int sizeInBytes, totalSize, err; |
||||||
|
+ int sizeInBytes, err; |
||||||
|
+ uint64_t totalSize; |
||||||
|
|
||||||
|
REQUEST(xChangePropertyReq); |
||||||
|
|
||||||
|
-- |
||||||
|
2.38.1 |
||||||
|
|
@ -0,0 +1,183 @@ |
|||||||
|
From bd134231e282d9eb126b6fdaa40bb383180fa72b Mon Sep 17 00:00:00 2001 |
||||||
|
From: Peter Hutterer <peter.hutterer@who-t.net> |
||||||
|
Date: Tue, 5 Jul 2022 11:11:06 +1000 |
||||||
|
Subject: [PATCH xserver 3/3] xkb: add request length validation for |
||||||
|
XkbSetGeometry |
||||||
|
|
||||||
|
No validation of the various fields on that report were done, so a |
||||||
|
malicious client could send a short request that claims it had N |
||||||
|
sections, or rows, or keys, and the server would process the request for |
||||||
|
N sections, running out of bounds of the actual request data. |
||||||
|
|
||||||
|
Fix this by adding size checks to ensure our data is valid. |
||||||
|
|
||||||
|
ZDI-CAN 16062, CVE-2022-2319. |
||||||
|
|
||||||
|
This vulnerability was discovered by: |
||||||
|
Jan-Niklas Sohn working with Trend Micro Zero Day Initiative |
||||||
|
|
||||||
|
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> |
||||||
|
(cherry picked from commit 6907b6ea2b4ce949cb07271f5b678d5966d9df42) |
||||||
|
--- |
||||||
|
xkb/xkb.c | 43 ++++++++++++++++++++++++++++++++++++++----- |
||||||
|
1 file changed, 38 insertions(+), 5 deletions(-) |
||||||
|
|
||||||
|
diff --git a/xkb/xkb.c b/xkb/xkb.c |
||||||
|
index 36464a770..27d19793e 100644 |
||||||
|
--- a/xkb/xkb.c |
||||||
|
+++ b/xkb/xkb.c |
||||||
|
@@ -5160,7 +5160,7 @@ _GetCountedString(char **wire_inout, ClientPtr client, char **str) |
||||||
|
} |
||||||
|
|
||||||
|
static Status |
||||||
|
-_CheckSetDoodad(char **wire_inout, |
||||||
|
+_CheckSetDoodad(char **wire_inout, xkbSetGeometryReq *req, |
||||||
|
XkbGeometryPtr geom, XkbSectionPtr section, ClientPtr client) |
||||||
|
{ |
||||||
|
char *wire; |
||||||
|
@@ -5171,6 +5171,9 @@ _CheckSetDoodad(char **wire_inout, |
||||||
|
Status status; |
||||||
|
|
||||||
|
dWire = (xkbDoodadWireDesc *) (*wire_inout); |
||||||
|
+ if (!_XkbCheckRequestBounds(client, req, dWire, dWire + 1)) |
||||||
|
+ return BadLength; |
||||||
|
+ |
||||||
|
any = dWire->any; |
||||||
|
wire = (char *) &dWire[1]; |
||||||
|
if (client->swapped) { |
||||||
|
@@ -5273,7 +5276,7 @@ _CheckSetDoodad(char **wire_inout, |
||||||
|
} |
||||||
|
|
||||||
|
static Status |
||||||
|
-_CheckSetOverlay(char **wire_inout, |
||||||
|
+_CheckSetOverlay(char **wire_inout, xkbSetGeometryReq *req, |
||||||
|
XkbGeometryPtr geom, XkbSectionPtr section, ClientPtr client) |
||||||
|
{ |
||||||
|
register int r; |
||||||
|
@@ -5284,6 +5287,9 @@ _CheckSetOverlay(char **wire_inout, |
||||||
|
|
||||||
|
wire = *wire_inout; |
||||||
|
olWire = (xkbOverlayWireDesc *) wire; |
||||||
|
+ if (!_XkbCheckRequestBounds(client, req, olWire, olWire + 1)) |
||||||
|
+ return BadLength; |
||||||
|
+ |
||||||
|
if (client->swapped) { |
||||||
|
swapl(&olWire->name); |
||||||
|
} |
||||||
|
@@ -5295,6 +5301,9 @@ _CheckSetOverlay(char **wire_inout, |
||||||
|
xkbOverlayKeyWireDesc *kWire; |
||||||
|
XkbOverlayRowPtr row; |
||||||
|
|
||||||
|
+ if (!_XkbCheckRequestBounds(client, req, rWire, rWire + 1)) |
||||||
|
+ return BadLength; |
||||||
|
+ |
||||||
|
if (rWire->rowUnder > section->num_rows) { |
||||||
|
client->errorValue = _XkbErrCode4(0x20, r, section->num_rows, |
||||||
|
rWire->rowUnder); |
||||||
|
@@ -5303,6 +5312,9 @@ _CheckSetOverlay(char **wire_inout, |
||||||
|
row = XkbAddGeomOverlayRow(ol, rWire->rowUnder, rWire->nKeys); |
||||||
|
kWire = (xkbOverlayKeyWireDesc *) &rWire[1]; |
||||||
|
for (k = 0; k < rWire->nKeys; k++, kWire++) { |
||||||
|
+ if (!_XkbCheckRequestBounds(client, req, kWire, kWire + 1)) |
||||||
|
+ return BadLength; |
||||||
|
+ |
||||||
|
if (XkbAddGeomOverlayKey(ol, row, |
||||||
|
(char *) kWire->over, |
||||||
|
(char *) kWire->under) == NULL) { |
||||||
|
@@ -5336,6 +5348,9 @@ _CheckSetSections(XkbGeometryPtr geom, |
||||||
|
register int r; |
||||||
|
xkbRowWireDesc *rWire; |
||||||
|
|
||||||
|
+ if (!_XkbCheckRequestBounds(client, req, sWire, sWire + 1)) |
||||||
|
+ return BadLength; |
||||||
|
+ |
||||||
|
if (client->swapped) { |
||||||
|
swapl(&sWire->name); |
||||||
|
swaps(&sWire->top); |
||||||
|
@@ -5361,6 +5376,9 @@ _CheckSetSections(XkbGeometryPtr geom, |
||||||
|
XkbRowPtr row; |
||||||
|
xkbKeyWireDesc *kWire; |
||||||
|
|
||||||
|
+ if (!_XkbCheckRequestBounds(client, req, rWire, rWire + 1)) |
||||||
|
+ return BadLength; |
||||||
|
+ |
||||||
|
if (client->swapped) { |
||||||
|
swaps(&rWire->top); |
||||||
|
swaps(&rWire->left); |
||||||
|
@@ -5375,6 +5393,9 @@ _CheckSetSections(XkbGeometryPtr geom, |
||||||
|
for (k = 0; k < rWire->nKeys; k++, kWire++) { |
||||||
|
XkbKeyPtr key; |
||||||
|
|
||||||
|
+ if (!_XkbCheckRequestBounds(client, req, kWire, kWire + 1)) |
||||||
|
+ return BadLength; |
||||||
|
+ |
||||||
|
key = XkbAddGeomKey(row); |
||||||
|
if (!key) |
||||||
|
return BadAlloc; |
||||||
|
@@ -5400,7 +5421,7 @@ _CheckSetSections(XkbGeometryPtr geom, |
||||||
|
register int d; |
||||||
|
|
||||||
|
for (d = 0; d < sWire->nDoodads; d++) { |
||||||
|
- status = _CheckSetDoodad(&wire, geom, section, client); |
||||||
|
+ status = _CheckSetDoodad(&wire, req, geom, section, client); |
||||||
|
if (status != Success) |
||||||
|
return status; |
||||||
|
} |
||||||
|
@@ -5409,7 +5430,7 @@ _CheckSetSections(XkbGeometryPtr geom, |
||||||
|
register int o; |
||||||
|
|
||||||
|
for (o = 0; o < sWire->nOverlays; o++) { |
||||||
|
- status = _CheckSetOverlay(&wire, geom, section, client); |
||||||
|
+ status = _CheckSetOverlay(&wire, req, geom, section, client); |
||||||
|
if (status != Success) |
||||||
|
return status; |
||||||
|
} |
||||||
|
@@ -5443,6 +5464,9 @@ _CheckSetShapes(XkbGeometryPtr geom, |
||||||
|
xkbOutlineWireDesc *olWire; |
||||||
|
XkbOutlinePtr ol; |
||||||
|
|
||||||
|
+ if (!_XkbCheckRequestBounds(client, req, shapeWire, shapeWire + 1)) |
||||||
|
+ return BadLength; |
||||||
|
+ |
||||||
|
shape = |
||||||
|
XkbAddGeomShape(geom, shapeWire->name, shapeWire->nOutlines); |
||||||
|
if (!shape) |
||||||
|
@@ -5453,12 +5477,18 @@ _CheckSetShapes(XkbGeometryPtr geom, |
||||||
|
XkbPointPtr pt; |
||||||
|
xkbPointWireDesc *ptWire; |
||||||
|
|
||||||
|
+ if (!_XkbCheckRequestBounds(client, req, olWire, olWire + 1)) |
||||||
|
+ return BadLength; |
||||||
|
+ |
||||||
|
ol = XkbAddGeomOutline(shape, olWire->nPoints); |
||||||
|
if (!ol) |
||||||
|
return BadAlloc; |
||||||
|
ol->corner_radius = olWire->cornerRadius; |
||||||
|
ptWire = (xkbPointWireDesc *) &olWire[1]; |
||||||
|
for (p = 0, pt = ol->points; p < olWire->nPoints; p++, pt++, ptWire++) { |
||||||
|
+ if (!_XkbCheckRequestBounds(client, req, ptWire, ptWire + 1)) |
||||||
|
+ return BadLength; |
||||||
|
+ |
||||||
|
pt->x = ptWire->x; |
||||||
|
pt->y = ptWire->y; |
||||||
|
if (client->swapped) { |
||||||
|
@@ -5564,12 +5594,15 @@ _CheckSetGeom(XkbGeometryPtr geom, xkbSetGeometryReq * req, ClientPtr client) |
||||||
|
return status; |
||||||
|
|
||||||
|
for (i = 0; i < req->nDoodads; i++) { |
||||||
|
- status = _CheckSetDoodad(&wire, geom, NULL, client); |
||||||
|
+ status = _CheckSetDoodad(&wire, req, geom, NULL, client); |
||||||
|
if (status != Success) |
||||||
|
return status; |
||||||
|
} |
||||||
|
|
||||||
|
for (i = 0; i < req->nKeyAliases; i++) { |
||||||
|
+ if (!_XkbCheckRequestBounds(client, req, wire, wire + XkbKeyNameLength)) |
||||||
|
+ return BadLength; |
||||||
|
+ |
||||||
|
if (XkbAddGeomKeyAlias(geom, &wire[XkbKeyNameLength], wire) == NULL) |
||||||
|
return BadAlloc; |
||||||
|
wire += 2 * XkbKeyNameLength; |
||||||
|
-- |
||||||
|
2.36.1 |
||||||
|
|
@ -0,0 +1,82 @@ |
|||||||
|
From be6bcbfa3f388ca0705db8baf10fa5c2d29b7d36 Mon Sep 17 00:00:00 2001 |
||||||
|
From: Peter Hutterer <peter.hutterer@who-t.net> |
||||||
|
Date: Tue, 29 Nov 2022 13:55:32 +1000 |
||||||
|
Subject: [PATCH xserver 4/7] Xi: disallow passive grabs with a detail > 255 |
||||||
|
|
||||||
|
The XKB protocol effectively prevents us from ever using keycodes above |
||||||
|
255. For buttons it's theoretically possible but realistically too niche |
||||||
|
to worry about. For all other passive grabs, the detail must be zero |
||||||
|
anyway. |
||||||
|
|
||||||
|
This fixes an OOB write: |
||||||
|
|
||||||
|
ProcXIPassiveUngrabDevice() calls DeletePassiveGrabFromList with a |
||||||
|
temporary grab struct which contains tempGrab->detail.exact = stuff->detail. |
||||||
|
For matching existing grabs, DeleteDetailFromMask is called with the |
||||||
|
stuff->detail value. This function creates a new mask with the one bit |
||||||
|
representing stuff->detail cleared. |
||||||
|
|
||||||
|
However, the array size for the new mask is 8 * sizeof(CARD32) bits, |
||||||
|
thus any detail above 255 results in an OOB array write. |
||||||
|
|
||||||
|
CVE-2022-46341, ZDI-CAN 19381 |
||||||
|
|
||||||
|
This vulnerability was discovered by: |
||||||
|
Jan-Niklas Sohn working with Trend Micro Zero Day Initiative |
||||||
|
|
||||||
|
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> |
||||||
|
Acked-by: Olivier Fourdan <ofourdan@redhat.com> |
||||||
|
--- |
||||||
|
Xi/xipassivegrab.c | 22 ++++++++++++++-------- |
||||||
|
1 file changed, 14 insertions(+), 8 deletions(-) |
||||||
|
|
||||||
|
diff --git a/Xi/xipassivegrab.c b/Xi/xipassivegrab.c |
||||||
|
index 2769fb7c94..c9ac2f8553 100644 |
||||||
|
--- a/Xi/xipassivegrab.c |
||||||
|
+++ b/Xi/xipassivegrab.c |
||||||
|
@@ -137,6 +137,12 @@ ProcXIPassiveGrabDevice(ClientPtr client) |
||||||
|
return BadValue; |
||||||
|
} |
||||||
|
|
||||||
|
+ /* XI2 allows 32-bit keycodes but thanks to XKB we can never |
||||||
|
+ * implement this. Just return an error for all keycodes that |
||||||
|
+ * cannot work anyway, same for buttons > 255. */ |
||||||
|
+ if (stuff->detail > 255) |
||||||
|
+ return XIAlreadyGrabbed; |
||||||
|
+ |
||||||
|
if (XICheckInvalidMaskBits(client, (unsigned char *) &stuff[1], |
||||||
|
stuff->mask_len * 4) != Success) |
||||||
|
return BadValue; |
||||||
|
@@ -207,14 +213,8 @@ ProcXIPassiveGrabDevice(ClientPtr client) |
||||||
|
¶m, XI2, &mask); |
||||||
|
break; |
||||||
|
case XIGrabtypeKeycode: |
||||||
|
- /* XI2 allows 32-bit keycodes but thanks to XKB we can never |
||||||
|
- * implement this. Just return an error for all keycodes that |
||||||
|
- * cannot work anyway */ |
||||||
|
- if (stuff->detail > 255) |
||||||
|
- status = XIAlreadyGrabbed; |
||||||
|
- else |
||||||
|
- status = GrabKey(client, dev, mod_dev, stuff->detail, |
||||||
|
- ¶m, XI2, &mask); |
||||||
|
+ status = GrabKey(client, dev, mod_dev, stuff->detail, |
||||||
|
+ ¶m, XI2, &mask); |
||||||
|
break; |
||||||
|
case XIGrabtypeEnter: |
||||||
|
case XIGrabtypeFocusIn: |
||||||
|
@@ -334,6 +334,12 @@ ProcXIPassiveUngrabDevice(ClientPtr client) |
||||||
|
return BadValue; |
||||||
|
} |
||||||
|
|
||||||
|
+ /* We don't allow passive grabs for details > 255 anyway */ |
||||||
|
+ if (stuff->detail > 255) { |
||||||
|
+ client->errorValue = stuff->detail; |
||||||
|
+ return BadValue; |
||||||
|
+ } |
||||||
|
+ |
||||||
|
rc = dixLookupWindow(&win, stuff->grab_window, client, DixSetAttrAccess); |
||||||
|
if (rc != Success) |
||||||
|
return rc; |
||||||
|
-- |
||||||
|
2.38.1 |
||||||
|
|
@ -0,0 +1,48 @@ |
|||||||
|
From 6b59bdddf30dde413c4e0391cf84f3b94d4b4e31 Mon Sep 17 00:00:00 2001 |
||||||
|
From: Peter Hutterer <peter.hutterer@who-t.net> |
||||||
|
Date: Tue, 29 Nov 2022 14:53:07 +1000 |
||||||
|
Subject: [PATCH xserver 5/7] Xext: free the screen saver resource when |
||||||
|
replacing it |
||||||
|
|
||||||
|
This fixes a use-after-free bug: |
||||||
|
|
||||||
|
When a client first calls ScreenSaverSetAttributes(), a struct |
||||||
|
ScreenSaverAttrRec is allocated and added to the client's |
||||||
|
resources. |
||||||
|
|
||||||
|
When the same client calls ScreenSaverSetAttributes() again, a new |
||||||
|
struct ScreenSaverAttrRec is allocated, replacing the old struct. The |
||||||
|
old struct was freed but not removed from the clients resources. |
||||||
|
|
||||||
|
Later, when the client is destroyed the resource system invokes |
||||||
|
ScreenSaverFreeAttr and attempts to clean up the already freed struct. |
||||||
|
|
||||||
|
Fix this by letting the resource system free the old attrs instead. |
||||||
|
|
||||||
|
CVE-2022-46343, ZDI-CAN 19404 |
||||||
|
|
||||||
|
This vulnerability was discovered by: |
||||||
|
Jan-Niklas Sohn working with Trend Micro Zero Day Initiative |
||||||
|
|
||||||
|
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> |
||||||
|
Acked-by: Olivier Fourdan <ofourdan@redhat.com> |
||||||
|
--- |
||||||
|
Xext/saver.c | 2 +- |
||||||
|
1 file changed, 1 insertion(+), 1 deletion(-) |
||||||
|
|
||||||
|
diff --git a/Xext/saver.c b/Xext/saver.c |
||||||
|
index f813ba08d1..fd6153c313 100644 |
||||||
|
--- a/Xext/saver.c |
||||||
|
+++ b/Xext/saver.c |
||||||
|
@@ -1051,7 +1051,7 @@ ScreenSaverSetAttributes(ClientPtr client) |
||||||
|
pVlist++; |
||||||
|
} |
||||||
|
if (pPriv->attr) |
||||||
|
- FreeScreenAttr(pPriv->attr); |
||||||
|
+ FreeResource(pPriv->attr->resource, AttrType); |
||||||
|
pPriv->attr = pAttr; |
||||||
|
pAttr->resource = FakeClientID(client->index); |
||||||
|
if (!AddResource(pAttr->resource, AttrType, (void *) pAttr)) |
||||||
|
-- |
||||||
|
2.38.1 |
||||||
|
|
@ -0,0 +1,74 @@ |
|||||||
|
From 40f06ae1bd12f4416df59382324a0d31ab2ba704 Mon Sep 17 00:00:00 2001 |
||||||
|
From: Peter Hutterer <peter.hutterer@who-t.net> |
||||||
|
Date: Wed, 30 Nov 2022 11:20:40 +1000 |
||||||
|
Subject: [PATCH xserver 6/7] Xext: free the XvRTVideoNotify when turning off |
||||||
|
from the same client |
||||||
|
|
||||||
|
This fixes a use-after-free bug: |
||||||
|
|
||||||
|
When a client first calls XvdiSelectVideoNotify() on a drawable with a |
||||||
|
TRUE onoff argument, a struct XvVideoNotifyRec is allocated. This struct |
||||||
|
is added twice to the resources: |
||||||
|
- as the drawable's XvRTVideoNotifyList. This happens only once per |
||||||
|
drawable, subsequent calls append to this list. |
||||||
|
- as the client's XvRTVideoNotify. This happens for every client. |
||||||
|
|
||||||
|
The struct keeps the ClientPtr around once it has been added for a |
||||||
|
client. The idea, presumably, is that if the client disconnects we can remove |
||||||
|
all structs from the drawable's list that match the client (by resetting |
||||||
|
the ClientPtr to NULL), but if the drawable is destroyed we can remove |
||||||
|
and free the whole list. |
||||||
|
|
||||||
|
However, if the same client then calls XvdiSelectVideoNotify() on the |
||||||
|
same drawable with a FALSE onoff argument, only the ClientPtr on the |
||||||
|
existing struct was set to NULL. The struct itself remained in the |
||||||
|
client's resources. |
||||||
|
|
||||||
|
If the drawable is now destroyed, the resource system invokes |
||||||
|
XvdiDestroyVideoNotifyList which frees the whole list for this drawable |
||||||
|
- including our struct. This function however does not free the resource |
||||||
|
for the client since our ClientPtr is NULL. |
||||||
|
|
||||||
|
Later, when the client is destroyed and the resource system invokes |
||||||
|
XvdiDestroyVideoNotify, we unconditionally set the ClientPtr to NULL. On |
||||||
|
a struct that has been freed previously. This is generally frowned upon. |
||||||
|
|
||||||
|
Fix this by calling FreeResource() on the second call instead of merely |
||||||
|
setting the ClientPtr to NULL. This removes the struct from the client |
||||||
|
resources (but not from the list), ensuring that it won't be accessed |
||||||
|
again when the client quits. |
||||||
|
|
||||||
|
Note that the assignment tpn->client = NULL; is superfluous since the |
||||||
|
XvdiDestroyVideoNotify function will do this anyway. But it's left for |
||||||
|
clarity and to match a similar invocation in XvdiSelectPortNotify. |
||||||
|
|
||||||
|
CVE-2022-46342, ZDI-CAN 19400 |
||||||
|
|
||||||
|
This vulnerability was discovered by: |
||||||
|
Jan-Niklas Sohn working with Trend Micro Zero Day Initiative |
||||||
|
|
||||||
|
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> |
||||||
|
Acked-by: Olivier Fourdan <ofourdan@redhat.com> |
||||||
|
--- |
||||||
|
Xext/xvmain.c | 4 +++- |
||||||
|
1 file changed, 3 insertions(+), 1 deletion(-) |
||||||
|
|
||||||
|
diff --git a/Xext/xvmain.c b/Xext/xvmain.c |
||||||
|
index f627471938..2a08f8744a 100644 |
||||||
|
--- a/Xext/xvmain.c |
||||||
|
+++ b/Xext/xvmain.c |
||||||
|
@@ -811,8 +811,10 @@ XvdiSelectVideoNotify(ClientPtr client, DrawablePtr pDraw, BOOL onoff) |
||||||
|
tpn = pn; |
||||||
|
while (tpn) { |
||||||
|
if (tpn->client == client) { |
||||||
|
- if (!onoff) |
||||||
|
+ if (!onoff) { |
||||||
|
tpn->client = NULL; |
||||||
|
+ FreeResource(tpn->id, XvRTVideoNotify); |
||||||
|
+ } |
||||||
|
return Success; |
||||||
|
} |
||||||
|
if (!tpn->client) |
||||||
|
-- |
||||||
|
2.38.1 |
||||||
|
|
@ -0,0 +1,36 @@ |
|||||||
|
From 9c70f90b24ba5de5eeb8a854c25f72a38d497fb7 Mon Sep 17 00:00:00 2001 |
||||||
|
From: Peter Hutterer <peter.hutterer@who-t.net> |
||||||
|
Date: Mon, 5 Dec 2022 15:55:54 +1000 |
||||||
|
Subject: [PATCH xserver 7/7] xkb: reset the radio_groups pointer to NULL after |
||||||
|
freeing it |
||||||
|
|
||||||
|
Unlike other elements of the keymap, this pointer was freed but not |
||||||
|
reset. On a subsequent XkbGetKbdByName request, the server may access |
||||||
|
already freed memory. |
||||||
|
|
||||||
|
CVE-2022-46283, ZDI-CAN-19530 |
||||||
|
|
||||||
|
This vulnerability was discovered by: |
||||||
|
Jan-Niklas Sohn working with Trend Micro Zero Day Initiative |
||||||
|
|
||||||
|
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> |
||||||
|
Acked-by: Olivier Fourdan <ofourdan@redhat.com> |
||||||
|
--- |
||||||
|
xkb/xkbUtils.c | 1 + |
||||||
|
1 file changed, 1 insertion(+) |
||||||
|
|
||||||
|
diff --git a/xkb/xkbUtils.c b/xkb/xkbUtils.c |
||||||
|
index dd089c2046..3f5791a183 100644 |
||||||
|
--- a/xkb/xkbUtils.c |
||||||
|
+++ b/xkb/xkbUtils.c |
||||||
|
@@ -1326,6 +1326,7 @@ _XkbCopyNames(XkbDescPtr src, XkbDescPtr dst) |
||||||
|
} |
||||||
|
else { |
||||||
|
free(dst->names->radio_groups); |
||||||
|
+ dst->names->radio_groups = NULL; |
||||||
|
} |
||||||
|
dst->names->num_rg = src->names->num_rg; |
||||||
|
|
||||||
|
-- |
||||||
|
2.38.1 |
||||||
|
|
@ -0,0 +1,35 @@ |
|||||||
|
From bb1711b7fba42f2a0c7d1c09beee241a1b2bcc30 Mon Sep 17 00:00:00 2001 |
||||||
|
From: Peter Hutterer <peter.hutterer@who-t.net> |
||||||
|
Date: Mon, 19 Dec 2022 10:06:45 +1000 |
||||||
|
Subject: [PATCH xserver] Xext: fix invalid event type mask in |
||||||
|
XTestSwapFakeInput |
||||||
|
|
||||||
|
In commit b320ca0 the mask was inadvertently changed from octal 0177 to |
||||||
|
hexadecimal 0x177. |
||||||
|
|
||||||
|
Fixes commit b320ca0ffe4c0c872eeb3a93d9bde21f765c7c63 |
||||||
|
Xtest: disallow GenericEvents in XTestSwapFakeInput |
||||||
|
|
||||||
|
Found by Stuart Cassoff |
||||||
|
|
||||||
|
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> |
||||||
|
--- |
||||||
|
Xext/xtest.c | 2 +- |
||||||
|
1 file changed, 1 insertion(+), 1 deletion(-) |
||||||
|
|
||||||
|
diff --git a/Xext/xtest.c b/Xext/xtest.c |
||||||
|
index 2985a4ce6e..dde5c4cf9d 100644 |
||||||
|
--- a/Xext/xtest.c |
||||||
|
+++ b/Xext/xtest.c |
||||||
|
@@ -502,7 +502,7 @@ XTestSwapFakeInput(ClientPtr client, xReq * req) |
||||||
|
|
||||||
|
nev = ((req->length << 2) - sizeof(xReq)) / sizeof(xEvent); |
||||||
|
for (ev = (xEvent *) &req[1]; --nev >= 0; ev++) { |
||||||
|
- int evtype = ev->u.u.type & 0x177; |
||||||
|
+ int evtype = ev->u.u.type & 0177; |
||||||
|
/* Swap event */ |
||||||
|
proc = EventSwapVector[evtype]; |
||||||
|
/* no swapping proc; invalid event type? */ |
||||||
|
-- |
||||||
|
2.38.1 |
||||||
|
|
Loading…
Reference in new issue