Skip to content

overlay: remove shell spawns in init_system_info() to avoid pressure-vessel seccomp failures - #1983

Open
kakra wants to merge 3 commits into
flightlessmango:masterfrom
kakra:fixes/seccomp-crashes-inside-pressure-vessel
Open

overlay: remove shell spawns in init_system_info() to avoid pressure-vessel seccomp failures#1983
kakra wants to merge 3 commits into
flightlessmango:masterfrom
kakra:fixes/seccomp-crashes-inside-pressure-vessel

Conversation

@kakra

@kakra kakra commented Mar 8, 2026

Copy link
Copy Markdown

This PR removes shell-based system info collection from init_system_info() and replaces it with native code paths.

Motivation

In Steam Runtime / pressure-vessel setups (notably via Wine + Vulkan layer), spawning /bin/sh pipelines from MangoHud can fail under runtime/seccomp constraints and produce noisy logs and host coredumps (e.g. dash).

By removing those shell callouts, MangoHud avoids this failure mode during initialization.

Ref: ValveSoftware/steam-runtime#804


Exact scope of this PR

init_system_info() no longer shells out for basic system info

Replaced shell pipelines with native logic:

  • ram:

    • before: sed on /proc/meminfo
    • now: sysinfo(2) (totalram * mem_unit, converted to KiB)
  • kernel:

    • before: uname -r shell call
    • now: uname(2) via utsname.release
  • cpu:

    • before: sed ... /proc/cpuinfo | sed 's/([^)]*)//g;s/ / /g' | tail -n1
    • now: direct /proc/cpuinfo parsing in C++, plus equivalent cleanup of parenthesized blocks/spacing
  • os:

    • before: sed on /etc/os-release for PRETTY_NAME
    • now: direct /etc/os-release parsing in C++, then quote removal

Environment mutation scope reduced

Because the above shell spawns are gone, LD_PRELOAD handling was narrowed down to only where subprocess spawning is still needed (Wine version probing path).

The disabled OpenGL/glxinfo callout block is guarded so re-enabling it cannot silently miss the required LD_PRELOAD workaround.

No broader refactors

This PR intentionally does not migrate every remaining external callout in the file. Only the init_system_info() shell pipelines are targeted to fix the runtime failure mode above.


Behavioral notes

  • Intended output stays consistent with prior behavior, including CPU-name cleanup semantics.
  • Main expected impact: no /usr/bin/dash coredumps in affected pressure-vessel scenarios.
  • Nice side effect: lower init overhead from avoiding shell/process startup (potentially visible as faster game start, and possibly less overhead if/when initialization paths are re-entered).

Future considerations

This change reduces getenv()/setenv() usage in one hot path, but the broader pattern still exists in other parts of the codebase.

Given MangoHud runs as a Vulkan layer inside the game process, process-global environment mutation is risky:

  • getenv()/setenv() are process-global and generally not a good fit for highly concurrent in-process code.
  • Behavior is timing-sensitive and can become hard to reason about across threads/components.
  • It may work most of the time, but failures are non-local and difficult to debug.

Follow-up work could:

  1. Audit all environment mutation/read patterns in layer/runtime paths.
  2. Minimize or eliminate process-global env writes in runtime code.
  3. Prefer explicit per-call process setup (where external tools are unavoidable), or native APIs that avoid subprocesses.
  4. Isolate remaining external callouts behind strict wrappers with clear threading/lifetime constraints.

@smcv

smcv commented Mar 9, 2026

Copy link
Copy Markdown
Contributor

In Steam Runtime / pressure-vessel setups (notably via Wine + Vulkan layer), spawning /bin/sh pipelines from MangoHud can fail under runtime/seccomp constraints

We don't know what component is applying these seccomp filters: it might be something "larger" than the Steam Linux Runtime / pressure-vessel container, or it might be something that runs inside the container, like Proton. SLR/PV itself does not add any seccomp rules.

@kakra

kakra commented Mar 9, 2026

Copy link
Copy Markdown
Author

We don't know what component is applying these seccomp filters: it might be something "larger" than the Steam Linux Runtime / pressure-vessel container, or it might be something that runs inside the container, like Proton. SLR/PV itself does not add any seccomp rules.

Yes, I agree, my statement wasn't precise here. But whatever the root cause of the observed crashes is, it uncovered problematic code paths in MangoHud which should be fixed no matter what happens elsewhere. I deliberately chose to not write "sandbox" here to support the fact that the pressure-vessel container isn't a security boundary. We don't know yet where the seccomp filter originates but MangoHud trips over it. These commits mitigate the crashes (but there are still other potential crash scenarios, with or without pressure-vessel / SRT).

Comment thread src/overlay.cpp Outdated
kakra added 3 commits March 15, 2026 17:46
When `glxinfo` is not called, setting up `MANGOHUD_RECURSION` is dead
code: we read, set and unset the variable without any effect.

Dropping this block also avoids unnecessary environment mutation
in-process. `getenv()`/`setenv()` are not thread-safe in general, so
avoiding them here reduces risk in multi-threaded contexts.

v2: Dropping this code completely instead of only disabling it as per
the discussion with @flightlessmango.

Ref: flightlessmango#1983 (comment)
Spawning a shell from inside pressure-vessel is fragile and can fail
due to seccomp constraints, causing noisy logs and host coredumps.

Replace the shell pipeline (`sh|sed|tail`) used in `init_system_info()`
with native parsing and Linux APIs where available. This avoids
subprocess creation entirely for the covered paths.

This does not address every shell-based code path yet (for example the
disabled OpenGL version reader could be migrated similarly), but that
is outside the scope of this change.

The primary goal is to prevent `/usr/bin/dash` crashes from the Steam
Runtime when MangoHud runs inside pressure-vessel.

Ref: ValveSoftware/steam-runtime#804
A previous commit removed subprocess spawners from `init_system_info()`.
This allows us to reduce `getenv()`/`setenv()` usage to the absolute
minimum and lower risk in multi-threaded contexts.

The environment workaround is now only applied around the remaining
subprocess call used to query the Wine version.

Also add a preprocessor error in the disabled OpenGL callout block so
the `LD_PRELOAD` workaround is not missed if that callout is re-enabled.
@kakra
kakra force-pushed the fixes/seccomp-crashes-inside-pressure-vessel branch from 8ae04a8 to 64dbedd Compare March 15, 2026 16:47
@kakra

kakra commented Mar 15, 2026

Copy link
Copy Markdown
Author

@flightlessmango Before I invest more time in this potentially to be removed code, is there a branch with your current refactoring progress, or are there plans when it is ready?

@kakra

kakra commented Mar 15, 2026

Copy link
Copy Markdown
Author

I just saw that shell.cpp already implements most of my ideas.

@flightlessmango

Copy link
Copy Markdown
Owner

The working branch is server2. It's a structural change shifting MangoHud to a server/client model, so the main areas to look at are the server and client directories. The concept of executing commands has not been implemented yet and the design is not finalized, so that part is still open for exploration or discussion

@kakra

kakra commented Mar 16, 2026

Copy link
Copy Markdown
Author

Thanks, I'll look at it. I think one focus area is that the Vulkan layer avoids mutating states it doesn't control, especially if thread safety is concerned (getenv/setenv), and avoid forking shell pipelines. It looks like a client/server model is a very good way to do that. I'm somewhat excited. :-)

@kakra

kakra commented Apr 22, 2026

Copy link
Copy Markdown
Author

With latest Proton Experimental (v11), I now see these:

# coredumpctl info 395606
           PID: 395606 (sh)
           UID: 1000 (kakra)
           GID: 1000 (kakra)
        Signal: 31 (SYS)
     Timestamp: Wed 2026-04-22 02:13:09 CEST (44s ago)
  Command Line: sh -c -- $'unset LD_PRELOAD; "/home/kakra/.local/share/Steam/steamapps/common/Proton - Experimental/files/lib/wine/x86_64-unix/wine64" --version'
    Executable: /usr/bin/dash
 Control Group: /user.slice/user-1000.slice/user@1000.service/app.slice/app-steam-app359320-395004.scope
          Unit: user@1000.service
     User Unit: app-steam-app359320-395004.scope
         Slice: user-1000.slice
     Owner UID: 1000 (kakra)
       Boot ID: b592954fa09240448c590b45cca33752
    Machine ID: 121b87ca633e8ac0016656680000001b
      Hostname: jupiter
       Storage: /var/lib/systemd/coredump/core.sh.1000.b592954fa09240448c590b45cca33752.395606.1776816789000000.zst (present)
  Size on Disk: 25.8K
       Message: Process 395606 (sh) of user 1000 dumped core.

                Stack trace of thread 395606:
                #0  0x000055b19a630544 __GI___getrlimit64 (/run/host/usr/lib64/libc.so.6 + 0xfe544)
                #1  0x000055b19a687ff0 __pthread_early_init (/run/host/usr/lib64/libc.so.6 + 0x155ff0)
                #2  0x00007fb2d2b776d9 dl_main (ld-linux-x86-64.so.2 + 0x216d9)
                #3  0x00007fb2d2b73ef3 _dl_sysdep_start (ld-linux-x86-64.so.2 + 0x1def3)
                #4  0x00007fb2d2b75554 _dl_start_final (ld-linux-x86-64.so.2 + 0x1f554)
                #5  0x00007fb2d2b74448 _start (ld-linux-x86-64.so.2 + 0x1e448)
                ELF object binary architecture: AMD x86-64

This is caused by the shell spawns which my patches didn't touch yet, notably spawning wine to read the wine version.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants