Skip to content

handle_surrounding_text: unbounded strlen() on untrusted Wayland protocol input causes SIGSEGV via Qt SSE2 page-boundary overread #132

@bhoglo

Description

@bhoglo

GitHub Issue Report — maliit-framework

Environment

Distro: Nobara Linux 43 (Fedora 43 based)
Architecture: x86_64
Compositor: kwin_wayland (KDE Plasma 6)
maliit-framework: 2.3.0-10.fc43
maliit-keyboard: 2.3.1-11.fc43
Qt: qt5-qtbase 5.15.18-1.fc43
Qt Wayland: qt5-qtwayland 5.15.18-1.fc43
Triggering application: Discord Flatpak (com.discordapp.Discord) running in Wayland native mode

Summary

maliit-keyboard can crash when processing a zwp_input_method_context_v1.surrounding_text event containing a very large or non-terminated text payload.

The crash occurs when the implementation performs an unbounded strlen() on the incoming text pointer before passing the result to QString::fromUtf8().

Reproduction

  1. Start a KDE Plasma Wayland session with maliit configured as the active input method.
  2. Launch Discord Flatpak in Wayland native mode.
  3. Focus a text input field inside Discord.
  4. Trigger a Discord renderer reload (this occurs periodically or during updates).

Result:

maliit-keyboard crashes with SIGSEGV.

KWin restarts the input method automatically, and the crash may repeat several times because the same Wayland event remains queued.

Observed Behavior

handle_surrounding_text receives a const char *text pointer from a Wayland surrounding_text event.

The pointer itself is valid but does not contain a null terminator within the immediately mapped memory region.

The implementation performs:

strlen(text)

with no upper bound.

If the pointer references memory without a nearby null byte, strlen() may traverse a very large region of heap memory (observed ~278 MB) before returning.

The resulting length is then passed to:

QString::fromUtf8(text, len)

During UTF‑8 conversion Qt performs vectorized reads, and when the read crosses a page boundary a SIGSEGV occurs.

Crash Signature

Faulting instruction:
QUtf8::convertToUnicode +144
movdqu (%rax), %xmm0

Notes

The surrounding_text payload originates from a Wayland client via the compositor and therefore should be treated as untrusted input.

A non-null pointer does not guarantee a bounded or valid C string.

Defensive length bounding before conversion would prevent scanning large memory regions or triggering crashes if malformed input is received.

Possible Mitigation

Using a bounded length check before conversion avoids unbounded memory reads:

size_t len = strnlen(text, MAX_SURROUNDING_TEXT);
QString s = QString::fromUtf8(text, len);

This ensures the conversion step operates on a safe, bounded buffer regardless of compositor or client behavior.

Workaround

Running Discord under XWayland avoids triggering the Wayland text-input event:

flatpak override --user --env=ELECTRON_OZONE_PLATFORM_HINT=x11 com.discordapp.Discord

Alternatively, disabling the virtual keyboard input method also prevents the crash.

Additional Evidence

rpm -V confirms packages are intact.
coredumpctl shows consistent crash offsets across occurrences.
Crash loops occur because the compositor restarts the input method while the malformed Wayland event remains queued.

Related Upstream Report

A related report has been filed with KWin regarding the compositor forwarding the surrounding_text payload without a size limit:

https://bugs.kde.org/show_bug.cgi?id=517620

That report focuses on compositor-side validation of the Wayland text-input event. This issue is filed here because maliit currently performs an unbounded strlen() on the incoming pointer, which allows malformed input to trigger a crash regardless of compositor behavior.

Defensive length bounding inside maliit would prevent the crash even if oversized or malformed surrounding_text events are received.

maliit-keyboard-coredump.txt

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions