Per our IRC conversation, the simplified overall architecture for steam is that there is a steam-client that is used as the entry point to everything Steam. From there you can purchase games and launch games. Part of its lifecycle is that the client must ptrace the games it launches.
The PR as implemented creates a steam-support
interface that allows the steam client to operate and launch games under the same security profile. In our IRC discussion I felt that it would be nice if the steam client and the games were under different security profiles such that the client could ptrace the games, but not the other way around. This would provide a nice security barrier for bad actors to ptrace the client and grab payment information. Yama actually prevents this when kernel.yama.ptrace_scope=1 and while yama defaults to ‘1’ in Ubuntu, yama may not be available everywhere, not to mention some people might have set it to ‘0’, so having the apparmor mediation is worthwhile.
I’ve proven to myself that the separation is possible by using an apparmor child profile. The concept is simple: the client runs like normal in its profile, but when it executes the game binaries, we have a Cx/cx rule that does a profile transition where the game runs in the child profile (the client does not need to be modified for this to work). This approach is completely workable within snapd, but it is a bit awkward in terms of maintenance since all steam game rules are tucked inside the steam-support child profile.
I then thought about yaml that easier to use for the steam-client snap and came up with:
name: steam-client
apps:
steam-client:
plugs:
- steam-support
- network
- removable-media
game:
plugs:
- steam-game
- network
- removable-media
- joystick
- ...
The new ‘steam-support’ interface has only what it needs to operate as the steam-client, ie, install, uninstall and launch games and has the ability to perform lifecycle duties on games. Instead of Cx/cx rules, we use a Px/px rule to perform an exec transition to snap.steam-client.game. The ‘steam-game’ interface has whatever is needed to run as a steam game that isn’t exposed via existing interfaces. In this manner, we can declare in the normal way what the client needs and what the games need, adding additional plugs to either as needed. This is also interesting because it leaves the possibility down the road to introduce different ‘game commands’ in the yaml that use different plugs to represent classes of games (eg, ‘mono-game’, ‘cef-game’, etc. The launcher would need to know which profile to launch them under of course).
What is slightly awkward about this approach is that we have the steam-client.game command that shows up in /snap/bin and isn’t really used for anything other than apparmor profile generation. We can turn this into a positive though and have steam-client.game be a shell script that simply says “You can purchase and launch games via ‘steam-client’”.
@ikey, let’s get some feedback from others before jumping on this in the PR. Once we decide on the path forward, I can advise on the next steps in the implementation.