Skip to content

interfaces: add a steam-support interface #11708

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Apr 29, 2022

Conversation

jhenstridge
Copy link
Contributor

This interface is intended to provide some additional permissions needed by the steam snap.

At present, this is primarily AppArmor and seccomp rules to allow Steam to launch pressure-vessel containers, which it uses to provide a consistent runtime environment to some games (at the moment mainly Windows games it runs under Proton/Wine). PV is based on Bubblewrap, as used by Flatpak and various other process sandboxes on GNOME systems.

Related to getting Steam games to run, I've added the futex_waitv syscall to the base template. Although the Ubuntu kernels don't yet support this syscall, we want to let Proton try to call it so it will fall back to the old futex API. As this has essentially the same security concerns as the existing futex syscalls, it seemed sensible to add it to the base template rather than the steam-support interface.

snap-seccomp knows about this syscall as of 15th April, when PR #11674 was merged.

@jhenstridge
Copy link
Contributor Author

The attempt to add support for futex_waitv didn't work, as it looks like snapd is being built against a too old libseccomp. It looks like we'd need libseccomp >= 2.5.4, which was released yesterday. I think it's currently being built with 2.5.3.

@mvo5 mvo5 added this to the 2.55 milestone Apr 22, 2022
@mvo5 mvo5 added Squash-merge Please squash this PR when merging. Needs security review Can only be merged once security gave a :+1: and removed Squash-merge Please squash this PR when merging. labels Apr 22, 2022
@{PROC}/@{pid}/gid_map rw,
@{PROC}/@{pid}/setgroups rw,
@{PROC}/@{pid}/mounts r,
@{PROC}/@{pid}/mountinfo r,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can these @{PROC}/@{pid}/ entries be reduced with an owner prefix? Unfortunately @{pid} doesn't yet mean "only this process's pid", so these rules are perhaps wider than intended.

# when performing a bind mount). Ideally we'd write a rule that
# requires the remount option in combination with any other, but
# AppArmor doesn't currently support that.
mount options in (rw, ro, nosuid, nodev, noexec, remount, bind, silent, relatime) -> /newroot/{,**},

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to write another eleven rules like the above, with smaller subsets of these?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mount calls this is intended to cover are from this code:

https://github.com/containers/bubblewrap/blob/main/bind-mount.c

It is working around the fact that calling mount() with MS_BIND causes it to ignore all flags passed other than MS_REC. So it is essentially doing the following:

  1. call mount(..., MS_BIND|MS_REC, ...) to perform the mount.
  2. parse /proc/self/mountinfo to discover the new mounts that have been created, and decode the mount flags used for each mount.
  3. for each new mount, bitwise or some additional flags to the existing flags. If the result is different, perform a mount(..., MS_SILENT|MS_BIND|MS_REMOUNT|new_flags,...) call to update the flags.

So the exact combination of flags will depend on the existing mounts on the system, which could include however the user has configured their host sytem, as that gets exposed through /var/lib/snapd/hostfs. So I think it'd be somewhat more than 12 possibilities if avoiding the in syntax.

I think the full enumeration would be the cross product of:

  1. silent, bind, remount, nosuid: always set
  2. nodev or nothing
  3. ro or rw
  4. noexec or nothing
  5. noatime or relatime or nothing
  6. nodiratime or nothing

So I think there are 48 possibilities. Does that sound about right?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, yikes, that code is far more dynamic than I expected. I thought I was going to see an array of a dozen directories plus their flags in the sources... Feel free to ignore this entirely, then. Thanks for the explanation.

Copy link

@metorino metorino left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general LGTM, but could you please add the owner rule qualifier as suggested by @setharnold so we keep the least privileges? Thanks!

This is a new syscall used to wait on multiple futexes at once, and
Wine/Proton will attempt to use it if the kernel supports it. Blocking
access prevents it from falling back to the other futex related
syscalls.
@jhenstridge jhenstridge force-pushed the iface-steam-support branch from 3d29f4e to 57cf149 Compare April 28, 2022 09:43
Copy link
Contributor

@mvo5 mvo5 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me, but someone closer to our current interfaces world like @mardy should review it.

@mvo5
Copy link
Contributor

mvo5 commented Apr 28, 2022

Also the unit tests are failing right now with:

----------------------------------------------------------------------
FAIL: basedeclaration_test.go:881: baseDeclSuite.TestPlugInstallation

basedeclaration_test.go:938:
    c.Check(err, IsNil, comm)
... value *errors.errorString = &errors.errorString{s:"installation not allowed by \"steam-support\" plug rule of interface \"steam-support\""} ("installation not allowed by \"steam-support\" plug rule of interface \"steam-support\"")
... steam-support

Copy link
Contributor

@mardy mardy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks! For now please ignore the nitpick comment about generating the rules, it's better to have this merged first. And in any case I'm not sure it would be a win, so we can safely disregard that :-)

#
# But that is not supported by AppArmor. So we enumerate the possible
# combinations of options Bubblewrap might use.
remount options=(bind, silent, nosuid, rw) /newroot/{,**},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might save some bytes if we generated this list programmatically, but it's probably not worth the effort (and if even, it should be a follow-up).

# Pivot from the intermediate root to sandbox root
mount options in (rw, silent, rprivate) -> /oldroot/,
umount /oldroot/,
pivot_root oldroot=/newroot/ /newroot/,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I learnt something new today! Nice! :-)

@jhenstridge jhenstridge marked this pull request as ready for review April 29, 2022 10:49
@pedronis pedronis self-requested a review April 29, 2022 12:56
Copy link
Collaborator

@pedronis pedronis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks not unreasonable, one question

/run/pressure-vessel/** mrw,
/run/host/usr/sbin/ldconfig* ixr,
/run/host/usr/bin/localedef ixr,
/var/cache/ldconfig/** rw,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does the snap does a layout on this one, as it comes from the base afaict?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we followup with that outside of this PR? I'd like @jhenstridge to respond, but we won't get that as timely as we'd like.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, these are in the pivoted root? but is still mount /var from the snap root, so still not entirely sure how that is writable

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added these rules to handle accesses made by the process within the mount namespace created by pressure-vessel/bubblewrap.

Maybe in future this could be separated out into a sub-profile, but that's complicated by the fact that the executables we'd perform the transitions on are downloaded by Steam and may have varying paths.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still a bit confused how that dir gets writable because the underlying dir comes from the base that is read-only

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can land this but I would like to understand how that gets writable by Monday. I'm probably missing something but I'm guessing what happens just looking at the rules here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The root of the bubblewrap sandbox is a tmpfs, so any path not mounted over is potentially writeable. It isn't exposing the whole host system /run or /var, so these locations are writeable (at least when AppArmor allows it).

@mvo5 mvo5 added the Squash-merge Please squash this PR when merging. label Apr 29, 2022
@pedronis pedronis self-assigned this Apr 29, 2022
@pedronis
Copy link
Collaborator

@jhenstridge I'm merging this but I would still like some better understanding of how that rw cache directory works on Monday.

@pedronis pedronis merged commit eaad8a2 into canonical:master Apr 29, 2022
mvo5 pushed a commit that referenced this pull request Apr 29, 2022
This interface is intended to provide some additional permissions needed by the steam snap.

At present, this is primarily AppArmor and seccomp rules to allow Steam to launch pressure-vessel containers, which it uses to provide a consistent runtime environment to some games (at the moment mainly Windows games it runs under Proton/Wine). PV is based on Bubblewrap, as used by Flatpak and various other process sandboxes on GNOME systems.

Related to getting Steam games to run, I've added the futex_waitv syscall to the base template. Although the Ubuntu kernels don't yet support this syscall, we want to let Proton try to call it so it will fall back to the old futex API. As this has essentially the same security concerns as the existing futex syscalls, it seemed sensible to add it to the base template rather than the steam-support interface.

snap-seccomp knows about this syscall as of 15th April, when PR #11674 was merged.

* interfaces: add a steam-support interface with permissions needed to set up pressure-vessel containers

* interfaces/seccomp: add futex_waitv to the base template

This is a new syscall used to wait on multiple futexes at once, and
Wine/Proton will attempt to use it if the kernel supports it. Blocking
access prevents it from falling back to the other futex related
syscalls.

* tests: add steam-support to policy snap

* interfaces: limit proc access to same owner in steam interface

* interfaces: lock down the remount AppArmor rules for steam-support

* interfaces: allow pressure-vessel to mount tmpfs to mask certain directories

* interfaces/policy: add base declaration tests for steam-support
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cherry-picked Needs security review Can only be merged once security gave a :+1: Squash-merge Please squash this PR when merging.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants