Skip to content
Snippets Groups Projects
  • Simon McVittie's avatar
    ba0ffa1e
    pv-wrap: Export parent dir of LD_PRELOAD modules, unless it's $HOME · ba0ffa1e
    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
    pv-wrap: Export parent dir of LD_PRELOAD modules, unless it's $HOME
    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>