protonscr

use-after-free access to X11 IM context pointers

steamclosed Web Component
ValveSoftware/steam-for-linux#13457 · opened 2026-07-28 by ghost · updated 2026-08-30 · 4 comments · github
?ghost 2026-07-28 github

Similar to [osu! #38423](https://github.com/ppy/osu/issues/38423) — use-after-free in X11 IM context handling
(triggered by IM daemon exit + window focus restoration).

Environment:

  • OS: Linux Mint 22.3 - Cinnamon 64-bit
  • Kernel: 6.14.0-37-generic
  • Steam version: 1.0.0.85 (Flatpak)
  • Display Server: X11
  • Mesa: 25.2.8
  • Input method framework: IBus

ibus-daemon

ibus-daemon does NOT trigger the crash because XOpenIM() fails in certain
environments (e.g., LANG=en_US.UTF-8), preventing Steam from caching an
IM context pointer in the first place.

Steps to verify:

  1. Start ibus-daemon - ibus-daemon -drx
  2. Start Steam (Flatpak)
  3. pkill ibus-daemon while steamwebhelper is active
  4. Window regains focus → steamwebhelper restarts automatically,
    Steam continues running normally (no crash, no core dump)

Note: The automatic restart is due to steamwebhelper's built-in recovery
mechanism, NOT a deliberate IM-specific workaround. Without a cached IM
context pointer, there is no use-after-free to crash on—the restart is
incidental, not causal.

steam[8984]: [2026-07-DD HH:MM:55] Destroy window
steam[8984]: Steam logging initialized: directory: /home/username/.var/app/com.valvesoftware.Steam/.local/share/Steam/logs
steam[8984]: [2026-07-DD HH:MM:55] ProcessNextMessage: socket disconnected
steam[8984]: [2026-07-DD HH:MM:55] No more messages are expected - exiting
steam[8984]: XOpenIM() failed, LANG = en_US.UTF-8
steam[8984]: XOpenIM() failed, LANG = en_US.UTF-8XRRGetOutputInfo Workaround: initialized with override: 0 real: 0xed28b7b0
steam[8984]: XRRGetCrtcInfo Workaround: initialized with override: 0 real: 0xed28a020

fcitx5

fcitx5 triggers the crash because XOpenIM() succeeds, causing Steam to
cache an IM context pointer. When fcitx5 terminates, the context is
destroyed, but both Steam processes retain dangling pointers.

Steps to reproduce:

  1. Start fcitx5 input method
  2. Start Steam (Flatpak)
  3. pkill fcitx5 while steamwebhelper is active
  4. Window regains focus → Use-after-free crashes:
    • steamwebhelper crashes in libX11.so at XSetICFocus (core dump at HH:21:16)
    • Steam main process segfaults in steamui.so ~20 seconds later (at HH:21:36)

Note: Both crashes are independent use-after-free events affecting the
same destroyed IM context object. Starting Steam before fcitx5 does not
trigger the issue because the IM context pointer is only cached if fcitx5
is already running at Steam startup.

See detailed root cause analysis, crash evidence, and suggested fixes
in the Update comment below.

?ghost 2026-07-28 github

FYI: While the initial crash appears in steamwebhelper, the underlying issue
is in Steam's IM context handling (libX11.so via SDL), which affects the main process
as well.
Might not be purely a Web Component issue.

?ghost 2026-07-28 github

Update:

Jul DD HH:21:16 host systemd-coredump[29523]: [🡕] Process 29236 (steamwebhelper) of user 1000 dumped core.
                                              
                                              Module /home/username/.var/app/com.valvesoftware.Steam/.local/share/Steam/ubuntu12_64/libSDL3.so.0 without build-id.
                                              Module /home/username/.var/app/com.valvesoftware.Steam/.local/share/Steam/ubuntu12_64/libSDL3.so.0
                                              Stack trace of thread 249:
                                              #0  0x00005c228e7a28b0 n/a (n/a + 0x0)
                                              ELF object binary architecture: AMD x86-64
Jul DD HH:21:16 host systemd[1]: [email protected]: Deactivated successfully.
Jul DD HH:21:36 host kernel: steam[29069]: segfault at e793a840 ip 00000000ed420e5d sp 00000000ffb69e8c error 4 in steamui.so[1510e5d,ecb93000+179c000] likely on CPU 4 (core 8, socket 0)
Jul DD HH:21:36 host kernel: Code: 45 d8 83 c4 10 8d 50 f4 3b 97 1c 09 00 00 0f 85 f1 00 00 00 8b 4d 08 83 ec 04 8b 45 e0 8b 51 0c 83 48 08 02 89 50 14 8b 41 38 <8b> 10 ff 71 0c 6a 12 50 ff 52 58 83 c4 10 89 45 d8 89 c6 89 fb ff
Jul DD HH:21:36 host systemd[1]: Started [email protected] - Process Core Dump (PID 29831/UID 0).
Jul DD HH:21:36 host systemd-coredump[29833]: [🡕] Process 29069 (steam) of user 1000 dumped core.
                                              
                                              Stack trace of thread 96:
                                              #0  0x00000000ed420e5d n/a (/home/username/.var/app/com.valvesoftware.Steam/.local/share/Steam/ubuntu12_32/steamui.so + 0x1511e5d)
                                              ELF object binary architecture: Intel 80386
Jul DD HH:21:36 host systemd[1]: [email protected]: Deactivated successfully.
Jul DD HH:21:36 host steam[28977]: /home/username/.var/app/com.valvesoftware.Steam/.local/share/Steam/steam.sh: line 966:    96 Segmentation fault         (core dumped) "$STEAMROOT/$STEAMEXEPATH" "$@"

Timeline:
steam crashes in steamui.so 20 secs after steamwebhelper crashes in libSDL3.so

root cause:

steamui.so+0x1511e5d:  mov    (%eax),%edx    ← eax = 0xe793a840(pointer to destroyed IM context)
steamui.so+0x1511e65:  call   *0x58(%edx)    ← Virtual function call on a destroyed object

The crash occurs at steamui.so+0x1511e5d when attempting to invoke a virtual
function on a destroyed X11 IM context object:

  • eax contains: 0xe793a840 (dangling pointer to freed IM context)
  • Instruction: mov (%eax),%edx → dereferences invalid memory
  • Followed by: call *0x58(%edx) → virtual function dispatch on destroyed object

Both Steam and steamwebhelper cache pointers to the same IM context; when the
IM daemon exits and destroys this context, both processes continue to hold stale
pointers, triggering use-after-free crashes.

Conclusion:

  1. Both Steam processes cache pointers to the same X11 IM context object
  2. When the IM daemon exits, this shared context is destroyed
  3. libSDL3.so and steamui.so both attempt to dereference this dangling pointer,
    causing independent crashes
  4. This is an application-level pointer management issue, not a library bug

Suggested Fix:
Steam should either (1) listen for IM daemon disconnection events and invalidate
cached IM context pointers, or (2) validate the cached IM context pointer before
each XSetICFocus call and gracefully fall back to non-IM text input if the
context has been destroyed.

KKontrabant 2026-07-28 github
Kkh4rit-bot 2026-08-30 github

Confirming this is still occurring on the current stable client, with a fully symbolized core dump, and that the shipped SDL3 predates the upstream fix.

System: Arch Linux (native install, not flatpak), Steam stable buildid 1785799196, libX11 1.8.13, fcitx5 5.1.21 as XIM server.

Crash: steamwebhelper SIGSEGV, SEGV_MAPERR, RIP=0x0. From the core: SDL3's X11_DispatchFocusIn passes its if (data->ic) guard and calls XSetICFocus; libX11's XSetICFocus tail-jumps through ic->methods->set_focus (jmp *0x8(%rax)), which reads NULL from the freed IC — so the PC lands on 0x0 with the return address still in libSDL3. The XIM server had been replaced (fcitx5 -rd) ~50 minutes earlier; libX11's _XimServerDestroy() freed the IM and all ICs at that point, and the crash fired on the first FocusIn afterwards. Classic use-after-free of the dangling XIC, exactly as described in this issue.

Why it still happens: the bundled ubuntu12_64/libSDL3.so.0 identifies as SDL-release-3.4.0-1163-g2d7f30078. Upstream commit 2d7f30078 is from 2026-07-14 — 56 commits behind the fix libsdl-org/SDL#16076 (63bf4c1c79, merged 2026-07-28, in release-3.4.14 as 105ad5e875). Consistent with that, the binary contains no "destroyCallback" string, i.e. the XNDestroyCallback registration from the fix isn't compiled in.

Repro: run Steam with an XIM input method active (XMODIFIERS=@im=fcitx), restart or replace fcitx5, focus any other window, then refocus a Steam window.

Could the bundled SDL3 be bumped to a snapshot containing 63bf4c1c79 (≥ 3.4.14)? Happy to provide the full backtrace/registers if useful.

Nothing extracted yet.