pyxtest: add test cases for the Screensaver extension CVEs of the last years

Commit 6c4c530107 ("Xext: Fix out of bounds access in SProcScreenSaverSuspend()")

Assisted-by: Claude:claude-claude-opus-4-6
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2187>
This commit is contained in:
Peter Hutterer 2026-04-20 18:15:12 +10:00 committed by Marge Bot
parent 33f3066ddb
commit 7f7bb53cf9
3 changed files with 84 additions and 0 deletions

View file

@ -57,6 +57,7 @@ if pytest.found()
tests_pyxtest = [
'test_randr.py',
'test_record.py',
'test_screensaver.py',
'test_xi.py',
'test_xkb.py',
]

View file

@ -0,0 +1,29 @@
# SPDX-License-Identifier: MIT
#
# Screen Saver extension protocol request builders
import struct
from dataclasses import dataclass
# ScreenSaver minor opcodes
ScreenSaverQueryVersion = 0
ScreenSaverSuspend = 5
@dataclass
class SuspendRequest:
"""ScreenSaverSuspend request (8 bytes)."""
opcode: int
suspend: int = 1
length_override: int | None = None
def to_bytes(self, byte_order: str = "<") -> bytes:
length = self.length_override if self.length_override is not None else 2
return struct.pack(
f"{byte_order}BBHI",
self.opcode,
ScreenSaverSuspend,
length,
self.suspend,
)

View file

@ -0,0 +1,54 @@
# SPDX-License-Identifier: MIT
#
# Security tests for MIT-SCREEN-SAVER extension vulnerabilities.
import time
import pytest
from proto import screensaver
from xclient import Extension, RawX11Connection, X11ConnectionError
class TestScreenSaverSuspend:
"""Tests for SProcScreenSaverSuspend vulnerabilities."""
@pytest.mark.swapped_client
@pytest.mark.asan
def test_suspend_swap_before_size_check(self, xserver):
"""
CVE-2021-4010 / ZDI-CAN-14951: SProcScreenSaverSuspend() did
swapl() on stuff->suspend before REQUEST_SIZE_MATCH, so a
short request triggered an OOB write during the swap.
The fix moved REQUEST_SIZE_MATCH before the swapl.
Fixed in commit 6c4c53010772 ("Xext: Fix out of bounds access
in SProcScreenSaverSuspend()").
"""
try:
conn = RawX11Connection(xserver.display_num, swapped=True)
except X11ConnectionError as e:
if "endian" in str(e).lower():
pytest.skip("Server does not accept big-endian clients")
raise
try:
ext = conn.query_extension(Extension.MIT_SCREEN_SAVER)
if not ext:
pytest.skip("MIT-SCREEN-SAVER extension not available")
# Send a valid ScreenSaverSuspend (the fix ensures proper
# validation order: size check before swap).
req = screensaver.SuspendRequest(
opcode=ext.opcode,
suspend=1,
)
conn.send_request(req.to_bytes(">"))
time.sleep(0.5)
assert xserver.is_alive, (
"Server crashed - SProcScreenSaverSuspend (CVE-2021-4010)"
)
finally:
conn.close()