protonscr

Steam games inherit many file descriptors from Steam

steamclosed
ValveSoftware/steam-for-linux#7971 · opened 2021-08-05 by smcv · updated 2024-12-05 · 2 comments · github
Ssmcv 2021-08-05 github

Your system information

  • Steam client version (build number or date): beta 2021-08-04, version 1628114775
  • Distribution (e.g. Ubuntu): Debian 11
  • Opted into Steam client beta?: yes
  • Have you checked for system updates?: yes

Please describe your issue in as much detail as possible:

When Steam launches a game, it does so with a lot of file descriptors open. The game could accidentally (or maliciously?) write to or read from these fds, disrupting intended Steam functionality.

I would expect that the vast majority of file descriptors that are open in Steam should have the close-on-execute (FD_CLOEXEC) flag set. This is most reliably done at open time, by specifying O_CLOEXEC for open(), modifier flag "e" for fopen(), SOCK_CLOEXEC for socket() and so on. At the moment, it looks as though only about 70% of them are close-on-execute.

Exceptions to this, where a file descriptor explicitly needs to be inherited by the game:

  • fd 0 (stdin) should always be open to either a terminal device or /dev/null. In practice it is inherited from whatever was Steam's stdin when it was launched, which seems correct.
  • fds 1 and 2 (stdout and stderr) should always be open to either a terminal device, a log file, a logging socket such as a sd_journal_stream_fd(), or /dev/null. In practice they are inherited from whatever was Steam's stdout/stderr when it was launched, which seems correct.
  • Steam might want the game to inherit a few IPC fds (pipe, socket, eventfd or shared memory) that it will use to communicate with the game or to help to detect whether the game has exited. If it does, I would expect that it would usually want to open these anew for each game.

Steps for reproducing this issue:

  1. Launch any game (I used Floating Point)
  2. Inspect the file descriptors that are open in the game, the game's reaper parent, the reaper's /bin/sh -c parent, and the main Steam process
  3. Expected result: The only fds that are inherited from Steam into /bin/sh and the reaper are 0, 1, 2, and maybe a small number of game-specific pipes etc. used for coordination between Steam and the reaper
  4. Actual result: On my test system, the main Steam process has 136 fds open, of which 44 are inherited by the /bin/sh -c process (and most of those end up in the game itself), including:
    • the ~/.steam/steam.pipe fifo, open for reading (if the game reads from this, then commands sent to Steam by other games or Steam instances will be lost)
    • several /dev/hidraw* devices (but presumably the game is meant to open these itself if it wants to use raw HID?)
    • several pipes, eventfds, epoll fds, etc. which are presumably only meant to be used internally by Steam
    • /dev/shm/u1000-ValveIPCSharedObj-Steam, open read/write
    • several /dev/shm/u1000-Shm_*, open read/write
    • the gameoverlayrenderer.so
    • the game's own remotecache.vdf, open for writing
    • Steam's own /proc/$pid/status
Ssmcv 2021-08-05 github

Games that use the Steam Linux Runtime container environment do not inherit these excess fds - they only receive fds 0, 1 and 2 from Steam - so it seems that none of the inherited fds >= 3 are strictly necessary.

Ssmcv 2024-12-05 github

steam-launch-wrapper now closes the excess fds.

Nothing extracted yet.