Games Team policy on games being setgid

Simon McVittie <[email protected]> Sun, 28 Dec 2025 15:46:52 +0000
Newsgroups gmane.linux.debian.devel.games
Message-ID <[email protected]>
Policy ยง11.11 says that games may be setgid games (2755 root:games) in 
order to access high score tables, saved games and so on. I think we 
should discourage this practice.

In particular, in cases where this has been added as a Debian-specific 
patch rather than being supported by the game's upstream developer, I 
think we should revert those patches and return the game to being 
completely unprivileged, even if this is a loss of functionality (no 
shared high-score tables on multi-user systems).

More details
------------

Typical uses of setgid games are:

* a high-score table /var/games/foogame is 0664 root:games, allowing
   foogame to maintain its high-score table system-wide
* or more general saved game state from one player might be used by
   another player, for example "bones files" in Nethack that result in
   the remains of a dead player character from a previous run appearing
   in a subsequent run
* or perhaps just tamper-proofing per-user saved games so that the
   player cannot easily cheat using an editor

... but to me, at least, using system-wide security mechanisms for these 
purposes seems rather like using a grenade to crack a nut.

Making a game setgid results in it running with more privileges than 
its caller. If the caller can trick the game into accessing files in 
ways that it was not intended to, using its setgid privilege, in ways 
that the caller would not be able to do, then that is arguably a 
security vulnerability (potentially resulting in the full CVE circus).

However, typical games have not been written to be hardened against a 
malicious caller supplying them with a crafted execution environment 
that will induce them to do things of the attacker's choice: the most 
obvious example is that they'll often completely trust attacker-supplied 
environment variables, in ways that provide the attacker with easy 
arbitrary code execution. Indeed, a lot of basic, expected functionality 
like X11 $DISPLAY and D-Bus $DBUS_SESSION_BUS_ADDRESS relies on the 
ability to inherit environment variables!

Even if the games themselves were hardened against a crafted execution 
environment, typical libraries used by games are not: for example SDL 
trusts and obeys many environment variables, without considering whether 
they might be attacker-supplied. Such libraries cannot be safely used by 
a setuid/setgid/setcap executable unless it sanitizes its execution 
environment before the first call into the library, for example checking 
environment variables against an allowlist. I'm 99% sure that we don't 
have any games that actually do this, and certainly we do have games that 
*don't* do this.

This might seem like a silly thing to be concerned about: in the typical 
historical use of the games group, for high score tables, one might 
reasonably assume that the worst-case scenario is that the attacker can 
cheat by recording an unattainably high score for themselves.

However, being setgid also opens up attack surface that game authors 
have not necessarily considered. A worst-case scenario here is: suppose 
users watson and moriarty share a multi-user system. watson is an avid 
player of some roguelike game that saves files in /var/games owned by 
group games (let's say foogame), and moriarty wishes to gain control 
over watson's account. If moriarty can find an exploitable vulnerability 
in foogame's saved game parsing code, then he can construct a crafted 
savegame to exploit that vulnerability, and use any game that can be 
tricked into overwriting arbitrary files with games group privileges 
(not just foogame! any game that shares the group!) to put it into 
place. The most extreme impact possible here is arbitrary code execution 
as user watson (account takeover), the next time watson plays foogame. 
To me, this seems too high a price to pay for shared high-score tables.

Other practical problems
------------------------

If a setgid game has a dependency tree that includes a library that 
does not support running setgid, and contains a safety-catch against 
accidentally doing so (GTK is a prominent example), then the game will 
simply not work. For example this is one of the few regressions I've 
found so far while trying to replace "classic" SDL2 with sdl2-compat: 
https://github.com/libsdl-org/sdl2-compat/issues/564, 
https://bugs.debian.org/1123953

Or, if a library tries its best to mitigate the security issues inherent 
in setgid (for example glibc, Mesa and Vulkan-Loader use secure_getenv() 
when they read environment variables), then functionality will be lost 
for setgid games (for example LD_LIBRARY_PATH, LIBGL_DRIVERS_PATH, 
GALLIUM_DRIVER and VK_LOADER_DEVICE_SELECT won't work as expected).

Suggested policy
----------------

Perhaps something like this:

Games should not be setuid or setcap.

New games should not be setgid.

Existing games should only be setgid games if not doing so would result 
in data loss or a serious loss of functionality. Ideally, they should 
migrate data into $HOME so that they do not need to continue to be 
setgid in every future Debian release.

Games that are setgid games should read the data that they need to read, 
and then irreversibly drop privileges (for example setresgid() setting 
the effective and saved gids equal to the real gid), before calling into 
non-trivial dependency libraries.

Games should not be setgid if their upstream developer does not 
intentionally support this.

Examples
--------

src:angband has explicit upstream support for being setgid games, in order 
to tamper-proof its saved games. My opinion is that this is security 
theatre that is unlikely to be worth the risk, and we should not have 
done this - although a transition from where we are now to the desired 
state without data loss might not be possible.

src:hannah has upstream code that writes to ~/.hannah [1] but has been 
patched (debian/patches/fix_score_dir.diff) to write scores to 
/var/games/hannah. I'm sure this seemed like a good idea in 2008, but I 
think we should not have done this, and I think we should remedy this by 
treating /var/games/hannah as read-only, and writing new high-scores 
into ~/.hannah, or even $XDG_DATA_DIR/Hannah.

See also
--------

* https://github.com/libsdl-org/SDL/issues/14717
* https://github.com/libsdl-org/sdl2-compat/issues/564,
   https://bugs.debian.org/1123953
* https://dwheeler.com/secure-programs/Secure-Programs-HOWTO/
   (in practice nobody writes games this way!)

----------------------------------------------------------------------

[1] actually /home/$USER/.hannah, but I think that's a bug, and it 
should be ~/.hannah rather than assuming that $HOME will always be 
/home/$USER