xserver/test/pyxtest/proto/x11.py
Peter Hutterer bea8d65fc8 test: add pytest-based test suite
This test suite is primarily aimed at reproducing the various CVE issues
we've had over the years that require custom crafted protocol requests.
It may also be useful for other testing.

Wrapped in python because pytest is a powerful test suite runner and
writing custom buffers is easy.

The architecture is so that we fork off an X server (one or more of
Xvfb, Xwayland, Xorg) and then run our test clients against that to
check whether we get the right reply, or crash the server, or whether
valgrind complains about something (valgrind is started automatically
for tests that are marked as such).

Tests can be run manually via pytest or via meson test.

Assisted-by: Claude:claude-claude-opus-4-6
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2187>
2026-05-10 23:42:43 +00:00

118 lines
2.7 KiB
Python

# SPDX-License-Identifier: MIT
#
# Core X11 protocol request builders
import struct
from dataclasses import dataclass
# Core protocol opcodes
CreateWindow = 1
CreatePixmap = 53
InternAtom = 16
QueryExtension = 98
def _pad(data: bytes) -> bytes:
"""Pad data to a 4-byte boundary."""
return data + b"\x00" * ((4 - len(data) % 4) % 4)
@dataclass
class CreateWindowRequest:
"""X11 CreateWindow request."""
wid: int
parent: int
x: int
y: int
width: int
height: int
depth: int
border_width: int = 0
window_class: int = 1 # InputOutput
visual: int = 0
value_mask: int = 0x0800 # override-redirect
override_redirect: int = 0
def to_bytes(self, byte_order: str = "<") -> bytes:
return struct.pack(
f"{byte_order}BBH II hhHHHH II I",
CreateWindow, # opcode
self.depth,
9, # request length in 4-byte units
self.wid,
self.parent,
self.x,
self.y,
self.width,
self.height,
self.border_width,
self.window_class,
self.visual,
self.value_mask,
self.override_redirect,
)
@dataclass
class CreatePixmapRequest:
"""X11 CreatePixmap request."""
pid: int
drawable: int
width: int
height: int
depth: int
def to_bytes(self, byte_order: str = "<") -> bytes:
return struct.pack(
f"{byte_order}BBHIIHH",
CreatePixmap, # opcode
self.depth,
4, # request length
self.pid,
self.drawable,
self.width,
self.height,
)
@dataclass
class InternAtomRequest:
"""X11 InternAtom request."""
name: str
only_if_exists: bool = False
def to_bytes(self, byte_order: str = "<") -> bytes:
name_bytes = self.name.encode("ascii")
padded = _pad(name_bytes)
req_len = (8 + len(padded)) // 4
return (
struct.pack(
f"{byte_order}BBHHxx",
InternAtom, # opcode
1 if self.only_if_exists else 0,
req_len,
len(name_bytes),
)
+ padded
)
@dataclass
class QueryExtensionRequest:
"""X11 QueryExtension request."""
name: str
def to_bytes(self, byte_order: str = "<") -> bytes:
name_bytes = self.name.encode("ascii")
padded = _pad(name_bytes)
req_len = (8 + len(padded)) // 4
return (
struct.pack(
f"{byte_order}BBHHxx", QueryExtension, 0, req_len, len(name_bytes)
)
+ padded
)