Blowing Off Steam: Let's plan steam-support interface

Long story short we’re going to need a specialist interface in snapd to handle the LSI snap, purely because its a very different creature to the ones we’re used to dealing with.

Before I go making PRs I wanna discuss this first from a security perspective, so I’m tagging @jdstrand into the convo here. Right now our initial steam-support interface is being prealpha tested in the Solus repos, and you can see our patch here:

https://dev.solus-project.com/source/snapd/browse/master/files/0001-interfaces-builtin-Add-new-steam-support-interface.patch

I basically need help in making this interface only ever autoconnect for the linux-steam-integration snap, as it pops a number of holes through apparmor to make games work. Now, the PCI and USB stuff can be largely ignored in the current patch as they won’t be sent in my first revision. The main thing to be concerned
about is the way in which games work, such as certain titles needing ptrace (Feral Interactive) or the lack of a PPID identifier in AppArmor to allow filtering the /proc/*/environ read for Game Dev Tycoon…

Then lastly there is the obvious issue that a great many of those paths (in /usr) are specific to the solus-runtime-gaming contents, which provide all the necessary support items to allow games using OpenAL to work, etc. The biggest hole popper I see in permissions is this:

########################
#      Disks/Media     #
########################

# Steam requires +x permissions on the partitions and will perform
# such a test:
# sh: /run/media/bigdisk/games//steamapps/.steam_exec_test.sh: /bin/sh: bad interpreter: Permission denied
/run/media/**/.steam_exec_test.sh ixmrw,

# Libraries and executables on other partitions require map + execute permissions
/run/media/**/steamapps/common/** ixm,

If we want folks to be able to play games on other partitions (Which, we really do) then we need to be able to execute the games from within the steamapps tree(s). So - any help that anyone can give me in securing the interface, and making it autoconnect only for LSI, will be GREATLY appreciated. The sooner we can get past this stage the sooner we can get LSI onto stable, and then move onto udev access (i.e. using my PS4 controller with the Steam snap :))

8 Likes

I’ll have a stab at it tomorrow. No promises wrt inclusion though :slight_smile:

EDIT: actually, can you just please propose your patch as a PR, we’ll take it from there.

Well I can’t send the PR without first discussing it, because I know the PR won’t be accepted. Thats kinda why I asked (17 days ago) for advice on writing interfaces…

I don’t know if it won’t be accepted. It doesn’t look bad in any way. Would you mind if I open a PR with your patch and discuss it with security?

It opens a lot of holes and ideally should only be used directly with the linux-steam-integration snap, and we’d want that guy to auto connect. I don’t think we want to make it so you can have any snap depend on it, surely?

Ah, that’s a curious case as this is a base snap and the interface would really have to be connected to just the “steam” snap that would probably be built on top. If this is a one-snap interface that is fine. If it has to be used by lots of snaps it is more of a problem.

Yeah its definitely a one-snap interface - and I wanna know how to forbid autoconnect for anything but linux-steam-integration :slight_smile:

Oh that one is easy, look for the base declaration snippets. Example things like lxd are a good candidate to see how this works. We have a way to make an interface only available to one snap.

2 Likes

@ikey Apologies for the delay. The last two weeks included some of us on holidays and then a sprint last week, so I’m personally behind on the forum and in PRs. But I’m back now and should get over these soon.

As for the interface, I think the easiest in this specific case is indeed to push the PR. In general those are almost entirely composed of poking holes, and then @jdstrand can provide details on the relevant entries right in context, which is easier.

As for auto-connections, we have a very rich language for those that can do anything desired and for very specific cases. We just need to know what to do and the rationale behind it.

3 Likes

OK I’ll poke lxd and figure out the hows (there is very little documentation on this subject) and then get a PR together.

It might have to go in tandem with another PR, because Solus just switched to glvnd. So that basically means we broke our own snap from our perspective. :slight_smile: It does mean we can nuke the old glx-provider statements though in the existing AppArmor bits

1 Like

I get that :slight_smile: I’m just trying to accelerate this as its tied into the direct goals of Solus itself, and unfortunately looks like I can’t hold back our release anymore to wait on these last bits in snapd.

PR basically copies the LXD scaffolding and I guess we go from there

I reviewed this forum topic and the PR then spoke with @ikey on IRC at length. I will be investigating a few things and report back here.

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.

Just to clarify, the Steam Client itself doesn’t need to do ptracing, only certain game launchers do, so they’d be satisfied by the child profile requirements. Also there is no real way for us to know ahead of time if a game is going to be using cef or mono, or any other technology, so defining those specific child profiles isn’t something that would make sense unless the Steam Client specifically executed them under a given apparmor profile.

For now the best path appears to be what we discussed on IRC, with a root level profile applying to anything not a game, and then a game profile allowing ptrace, etc, matching on the child paths.

OK so I’ve played with this some this morning, and two glaring issues come to mind so far.

Cx drops the environment of required variables like LD_PRELOAD, which LSI needs, so we’d want cx… Additionally any time we define a glob for changing the profile it conflicts with half of the built-in profiles and apparmor fails to parse:

profile has merged rule with conflicting x modifiers
ERROR processing regexs for profile snap.linux-steam-integration.exec, failed to load

Basically all the glob ones get merged and we’re unable to overwrite it unless we use exact paths (which we can’t because we don’t know them). Note this isn’t just on removable-media but even on @{HOME} paths, meaning I’m just not going to be able to change the child profile on the fly using globs. So it looks like we’re back to square 1 with a “super profile”.

We’re actually not back to square one; the conflicting x modifiers is part of the reason why I suggested not jumping on this PR just yet. :wink: We’ll need to carve out the paths in at least SNAP_USER_COMMON. removable-media should be ok though since we don’t have ix rules in there. Does the steam client actually need home? My understanding was it actually only needed SNAP_USER_COMMON, but if it does, we need to do the same for home.

I’m not sure what you mean by “carve out the paths” - can you elaborate please?

And we’ll need to allow home for now for people having setups like ~/SteamLibrary that are migrating to the snap

Or we allow ~/SteamLibrary in steam-support and steam-game (eg, is all of home actually needed?).

And by carve out, I mean adjust the default policy/affected interfaces that cause the conflicting x modifiers to specify ix for those paths so that steam-support can specify Px for them.

This is what I was going to provide to you and was trying to shield you from. :wink: