xkb: Fix off-by-one and NULL dereferences in _CheckSetOverlay()

Off-by-one in rowUnder validation: the bounds check uses '>' instead
of '>=' when comparing rWire->rowUnder against section->num_rows.
Since num_rows is a count and valid indices are 0 to num_rows-1,
rowUnder == num_rows passes the check but is one past the valid range.
XkbAddGeomOverlayRow() uses this as an array index, causing an
out-of-bounds read on section->rows[].

And throw in two alloc checks while we're at it.

Assisted-by: Claude:claude-claude-opus-4-6
(cherry picked from commit ed19312c4b)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2225>
This commit is contained in:
Peter Hutterer 2026-04-18 07:35:53 +10:00 committed by Alan Coopersmith
parent ce02d03020
commit fee9a11d89

View file

@ -5357,6 +5357,8 @@ _CheckSetOverlay(char **wire_inout, xkbSetGeometryReq *req,
}
CHK_ATOM_ONLY(olWire->name);
ol = XkbAddGeomOverlay(section, olWire->name, olWire->nRows);
if (!ol)
return BadAlloc;
rWire = (xkbOverlayRowWireDesc *) &olWire[1];
for (r = 0; r < olWire->nRows; r++) {
register int k;
@ -5366,12 +5368,14 @@ _CheckSetOverlay(char **wire_inout, xkbSetGeometryReq *req,
if (!_XkbCheckRequestBounds(client, req, rWire, rWire + 1))
return BadLength;
if (rWire->rowUnder > section->num_rows) {
if (rWire->rowUnder >= section->num_rows) {
client->errorValue = _XkbErrCode4(0x20, r, section->num_rows,
rWire->rowUnder);
return BadMatch;
}
row = XkbAddGeomOverlayRow(ol, rWire->rowUnder, rWire->nKeys);
if (!row)
return BadAlloc;
kWire = (xkbOverlayKeyWireDesc *) &rWire[1];
for (k = 0; k < rWire->nKeys; k++, kWire++) {
if (!_XkbCheckRequestBounds(client, req, kWire, kWire + 1))