Skip to content
Snippets Groups Projects
Simon McVittie's avatar
Simon McVittie authored
LD_PRELOAD modules are an inherently fragile mechanism, and any symbols
exported by either a LD_PRELOAD module or its direct dependencies
will "interpose" in front of symbols of the same name from any other
library. In some cases this can lead to crashes, for example when
the Python ctypes module from Steam Runtime 2 'soldier' (which depends
on libffi.so.6) gets its libffi references resolved to symbols from
a more modern host system's libffi.so.7 or libffi.so.8 pulled in by
the dependency chain:

    libMangoHud.so -> libwayland-client.so.0 -> libffi.so.8

Authors of LD_PRELOAD modules like MangoHud can avoid this situation
by making their LD_PRELOAD module only depend on highly long-term-stable
projects (ideally only glibc), and then loading the implementation of
its real functionality via `dlopen()`, using `RTLD_LOCAL|RTLD_DEEPBIND`
to avoid symbol conflicts.

For example, newer versions of MangoHud separate the module into
libMangoHud_shim.so (the actual LD_PRELOAD module, no dependencies
except glibc) and libMangoHud_opengl.so (dlopen'd by the shim module,
depends on whatever it needs to depend on).

This is a good approach and we should encourage it, but in the current
pressure-vessel codebase it isn't going to be completely reliable for
modules that are installed other than in /usr: for libMangoHud_shim.so
to be able to load libMangoHud_opengl.so, we need to ensure that they
are both visible in the filesystem of the game's container. However,
since we can't know what modules and/or libraries libMangoHud_shim.so
is going to load at runtime, we will have to use a heuristic.

The heuristic I've chosen here is to say that if you have
`LD_PRELOAD=/path/to/some/module.so`, then instead of sharing
`/path/to/some/module.so` with the container as we did previously,
we should share the parent directory `/path/to/some/`. In particular,
this is enough for MangoHud's requirements.

However, one notable exception is that if the module is situated
directly inside `$HOME`, and we are using `--unshare-home` to avoid
sharing the home directory with the container, we probably do not want
to overrule that. In this case, users will still need to use
`PRESSURE_VESSEL_FILESYSTEMS_RO` to share the dependency explicitly.

steamrt/tasks#595

Signed-off-by: default avatarSimon McVittie <smcv@collabora.com>
ba0ffa1e
History

steam-runtime-tools — Steam Runtime integration for the Steam client

The steam-runtime-tools library provides low-level Unix-specific tools and functionality for the Steam client, including the pressure-vessel tool that runs Steam games in containers.

To support multiple architectures (currently only i386, x86_64 and aarch64 are supported), you will need to build it once for each architecture and install at least the helper tools in /usr/libexec/steam-runtime-tools-0 (the libsteam-runtime-tools-0-helpers package) for every architecture in parallel.

The helper tools are located relative to the shared library, so it's OK to bundle steam-runtime-tools alongside some other stack in this layout:

anything/
    lib/
        x86_64-linux-gnu/
            libsteam-runtime-tools-0.so.0
    libexec/
        steam-runtime-tools-0/
            i386-linux-gnu-*
            x86_64-linux-gnu-*

as long as the program that is linked to libsteam-runtime-tools-0.so.0 can find it (via a RPATH or RUNPATH or by setting the LD_LIBRARY_PATH environment variable).

pressure-vessel — putting Steam in containers

The pressure-vessel/ subdirectory of this project contains the pressure-vessel utilities, which are used by Steam's Steam Linux Runtime (container runtime) compatibility tool to run games in individual game-specific containers. For background on pressure-vessel and the Steam Linux Runtime, please see: