mirror of
https://gitlab.freedesktop.org/xorg/xserver.git
synced 2026-06-06 22:18:24 +02:00
test/pyxtest: add test for XKB mapWidths stack OOB write (ZDI-CAN-30161)
Add a regression test that reproduces the mapWidths stack buffer overflow in CheckKeyTypes. The test sends two XkbSetMap requests: first with firstType=0, nTypes=255, ResizeTypes to expand the type table to 255 entries, then with firstType=255, nTypes=10, ResizeTypes. The second request passes the firstType > num_types check (255 > 255 is false) and computes nMaps = 255 + 10 = 265. Without the fix, the loop would write mapWidths[255..264], overflowing 9 bytes past the 256-element stack buffer into adjacent stack variables. Assisted-by: Claude:claude-opus-4-6 Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2228>
This commit is contained in:
parent
375d65aa2e
commit
6671daeada
1 changed files with 79 additions and 0 deletions
|
|
@ -670,3 +670,82 @@ class TestXkbSetMapNumLevels:
|
|||
assert xserver.is_alive, (
|
||||
"Server crashed - numLevels > XkbMaxShiftLevel (ZDI-CAN-30160)"
|
||||
)
|
||||
|
||||
|
||||
class TestXkbSetMapMapWidths:
|
||||
"""Tests for XKB SetMap mapWidths stack buffer overflow."""
|
||||
|
||||
@pytest.mark.asan
|
||||
def test_mapwidths_stack_oob_write(self, xserver, xkb_xclient):
|
||||
"""
|
||||
ZDI-CAN-30161: CheckKeyTypes computes nMaps = firstType + nTypes
|
||||
from client-controlled fields when XkbSetMapResizeTypes is set.
|
||||
mapWidths[] is a stack-allocated CARD8 array of 256 elements.
|
||||
No upper bound was enforced on nMaps.
|
||||
|
||||
Attack: First, SetMap(firstType=0, nTypes=255, ResizeTypes)
|
||||
sets num_types to 255. Then SetMap(firstType=255, nTypes=10,
|
||||
ResizeTypes) passes the check firstType > num_types (255 > 255
|
||||
is false) and computes nMaps=265. The loop then writes
|
||||
mapWidths[255..264], overflowing 9 bytes past the stack buffer.
|
||||
|
||||
Fixed by rejecting requests where firstType + nTypes exceeds
|
||||
the mapWidths buffer size (XkbMaxLegalKeyCode + 1 = 256).
|
||||
"""
|
||||
xclient, opcode = xkb_xclient
|
||||
|
||||
# Step 1: SetMap with firstType=0, nTypes=255 to set num_types=255.
|
||||
# All types must have valid numLevels.
|
||||
types_payload = b""
|
||||
# Type 0: numLevels=1
|
||||
types_payload += xkb.KeyTypeWire(num_levels=1).to_bytes()
|
||||
# Types 1-3: numLevels=2
|
||||
for _ in range(3):
|
||||
types_payload += xkb.KeyTypeWire(num_levels=2).to_bytes()
|
||||
# Types 4-254: numLevels=1
|
||||
for _ in range(251):
|
||||
types_payload += xkb.KeyTypeWire(num_levels=1).to_bytes()
|
||||
|
||||
req = xkb.SetMapRequest(
|
||||
opcode=opcode,
|
||||
present=xkb.XkbKeyTypesMask,
|
||||
flags=xkb.XkbSetMapResizeTypes,
|
||||
first_type=0,
|
||||
n_types=255,
|
||||
min_key_code=8,
|
||||
max_key_code=255,
|
||||
payload=types_payload,
|
||||
)
|
||||
xclient.send_request(req.to_bytes())
|
||||
xclient.flush_responses(timeout=0.5)
|
||||
|
||||
# Step 2: SetMap with firstType=255, nTypes=10, ResizeTypes.
|
||||
# nMaps = 255 + 10 = 265, which exceeds mapWidths[256].
|
||||
# Without the fix, this writes past the stack buffer.
|
||||
types_payload2 = b""
|
||||
for _ in range(10):
|
||||
types_payload2 += xkb.KeyTypeWire(num_levels=1).to_bytes()
|
||||
|
||||
req = xkb.SetMapRequest(
|
||||
opcode=opcode,
|
||||
present=xkb.XkbKeyTypesMask,
|
||||
flags=xkb.XkbSetMapResizeTypes,
|
||||
first_type=255,
|
||||
n_types=10,
|
||||
min_key_code=8,
|
||||
max_key_code=255,
|
||||
payload=types_payload2,
|
||||
)
|
||||
xclient.send_request(req.to_bytes())
|
||||
resps = xclient.flush_responses(timeout=0.5)
|
||||
errors = [r for r in resps if isinstance(r, X11Error)]
|
||||
|
||||
# On a patched server, CheckKeyTypes rejects nMaps > XkbMaxLegalKeyCode + 1.
|
||||
assert errors, (
|
||||
"SetMap with firstType=255 nTypes=10 was accepted - "
|
||||
"server is missing the nMaps upper bound check (ZDI-CAN-30161)"
|
||||
)
|
||||
|
||||
assert xserver.is_alive, (
|
||||
"Server crashed - mapWidths stack OOB write (ZDI-CAN-30161)"
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue