Skip to content
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

Isolate game processes for security reasons #670

Closed
fasterthanlime opened this issue May 26, 2016 · 30 comments
Closed

Isolate game processes for security reasons #670

fasterthanlime opened this issue May 26, 2016 · 30 comments
Labels
security Keep the baddies out

Comments

@fasterthanlime
Copy link
Collaborator

fasterthanlime commented May 26, 2016

Rough summary:

  • itch launches native games
  • native games have full access to the filesystem etc.
  • the filesystem might contain stuff we don't want games to access, such as
    • credentials
    • personal data
  • running games as another, less-privileged user (that doesn't have read access to files from the "real" user) seems like the way to go
  • barring that, a sandbox approach, but everybody knows sandboxes love to be broken
@fasterthanlime
Copy link
Collaborator Author

This is blocked by #671

@fasterthanlime
Copy link
Collaborator Author

Addressed itchio/butler#55 — good first step

@fasterthanlime
Copy link
Collaborator Author

fasterthanlime commented Jun 2, 2016

Investigated on OSX: and — oh boy, Apple does not want you to add another user and/or run GUI applications under it. It looks like there might be a way, by installing a launchd ticket service or something? (cf. pmuser)

After some more research, it looks like sandbox-exec might be a better solution to our problem, see this 2011 Apple Sandbox Guide (still relevant apparently).

On Linux, there are similar sandboxing mechanisms (SELinux/AppArmor, not the same on Fedora and Ubuntu though.. might have to lock down which distros we support), looks like the "run as a less privileged user" approach is only required on Windows?

@fasterthanlime fasterthanlime added the security Keep the baddies out label Jun 2, 2016
@fasterthanlime
Copy link
Collaborator Author

fasterthanlime commented Jun 3, 2016

Results of research

On OSX

Running as an other user is not practical because OSX distinguishes UID and "Mach execution context". Using "su" or "sudo" doesn't switch Mach execution contexts, and so the process is forbidden from connecting to WindowServer, etc. The way to work around this is to have a graphical login session running as the other user, and then use "sudo /bin/launchctl bsexec PID -u UID cmd args" where PID is the PID of the login session process of the other user. That's the only way to switch Mach execution contexts, and Apple advise against it, AND it requires sudo/root. Since we need to do that every time we launch a game, that's not practical.

There's also a way to disable the check that prevents processes from connecting to another user's WindowServer - but that would defeat some of the security features of newer OSXes, and can only be done system-wide, so that's not feasible either.

However, the sandboxing system on MacOS seems well-designed and practical for our purposes. For example:

  • sandbox-exec does not require superuser privilege
  • sandbox configuration files (*.sb files, see /System/Library/Sandbox/) are lisp/scheme-y files with a straightforward syntax, and can operate either in blacklist or in whitelist mode.

Here's a video example of using a simple sandbox policy to prevent the app from accessing saved credentials.

Note that a blacklist approach like shown in the video is risky - an attacker could for instance write to one of the non-protected paths (such as ~/.bashrc, ~/.zshrc, or anything automatically sourced) to steal the credentials later. A whitelist approach seems better (and more consistent with other OSes), but requires more research / studying Apple's existing policies more closely.

On Linux

After trying a gazillion things, not planning on messing with SELinux (Fedora) or AppArmor (Ubuntu) for now. That would require resources we don't have. However, by default, sensitive files (like Chrome cookies files) are in a folder that's 0700, which means other users cannot access them.

Adding a user on Linux is straightforward, provided we can rely on useradd (or is it adduser? could make the code use either, need to figure out which is the most common). chown-ing game directories so that they belong to itch-player seems like it shouldn't be a problem - but they shouldn't even need to belong to that user as long as they have g+r (group read) or o+r (other read).

Running games as another user is trickier. Most existing literature describes how to run things as root, because everyone is obsessed with root. However, we want to run it as a less privileged user. As a result:

  • Using sudo would require entering the password for the current user - and assumes the current user is an "administrator". That would be needed on every game launch, thus it's not practical.
  • Using su requires piping the password to its stdin - and thus, we lose the stdin for a given process (bye bye command-line games).

It looks like we might be able to use "setuid" for this. While it's - here again - usually used to run stuff as root ("passwd", "htop" on OSX, etc.) but we want to use it to run stuff as "itch-player". So, we need a "trampoline" executable (not a shell script) that is "chown itch-player" and "chmod u+s" (setuid), and acts like https://github.com/itchio/elevate - inheriting stdin+stderr+stdout, and passing command-line arguments. @greut's comment suggests a better approach to this

Another issue with launching processes as "itch-player" is that, by default, the X server will refuse connections. However, a simple xhost +si:localuser:itch-player can fix this. Shouldn't be harmless to run it once before every game launch, "just to be sure" (it won't generate duplicate files or anything, doesn't require root/sudo, etc.)

On Windows

Windows has no public-facing concept of sandboxing (afaict), the only solutions I could find are commercial software focused on generating "Portable apps" packages.

However, adding a user on Windows is easy (net user username password /ADD), granting read permissions to a folder is easy (icacls "C:\somewhere\*" /grant username:F /t - 'F' for full control, '/t' for recursive), and running (even a GUI) process as another user is super easy too (runas /user:username "C:\somewhere\somewhere.exe args") although it requires typing the password into stdin.

Instead of using runas.exe directly, we should probably use elevate.exe instead and pass the randomly-generated password to the itch-player account via some other mean. The proper Win32 call is CreateProcessWithLogonW

Here's Overland running as itch-player:

overland-as-itch-player

Summary

There are solutions for all 3 major OSes that:

  • Only require root/sudo for initial setup (upon upgrading to the latest version of the itch app)
  • Do not weaken built-in OS security measures in any way
  • Provide reasonable protection against automatic stealing of credentials by apps installed+launched via the itch app

Of course, these measures do not prevent scenarios in which the victim collaborates with the attacker, such as:

  • Downloading & running untrusted files from the internet (outside the itch app)
  • Giving physical access to their computer

..but that's the not the goal of this current security project. (Google Chrome's security model only cares about attacks that come from inside the browser, not from outside. Similarly, Mac OS is paranoid about Mac App Store apps, not about randomly downloaded stuff.)

@fasterthanlime fasterthanlime changed the title Run games as another user for security reasons Isolate game processes for security reasons Jun 3, 2016
@leafo
Copy link
Member

leafo commented Jun 3, 2016

On windows, when someone goes to boot up their computer does that mean they'll now see an itch-player account as an option? Could be annoying/confusing if so.

@greut
Copy link

greut commented Jun 3, 2016

@fasterthanlime with this construct, you don't need the trampoline binary.

# /etc/sudoers.d/itch
user ALL=NOPASSWD: /.../itch-player

@fasterthanlime
Copy link
Collaborator Author

On windows, when someone goes to boot up their computer does that mean they'll now see an itch-player account as an option? Could be annoying/confusing if so.

Apparently, it's possible to modify the registry to hide the user from login.

@hishamhm
Copy link

hishamhm commented Jun 7, 2016

One detail that might be worth noting is that, if you install all games as the less-privileged itch-player user, a game won't have access to the rest of the system, but it will have access to other games. I don't know how problematic this might be for you (malware-game deleting well-known-game's savegames just for pure evil?).

(In Android, the system essentially launches each app as a different user (note the various u0_a### users in this screenshot). They can pull it off because the concept of OS users stays pretty hidden there, but on Linux people will surely complain if they see a hundred extra entries in /etc/passwd.)

In GoboLinux we use a less-privileged of this kind for compiling programs, and we give it temporary access and we used to block parallel installs (we've since moved to other solutions). I don't know if you guys allow running multiple games at the same time... but if you don't, one way to solve this would be to only make the root directory of the "current game" traversable. Beyond this, I think you'd have to use more complicated container-style tricks such as launching subprocesses with their own mount tables, which you could then use to hide the other games from the current process.

@fasterthanlime
Copy link
Collaborator Author

I don't know how problematic this might be for you (malware-game deleting well-known-game's savegames just for pure evil?).

That's a pretty innocent threat (and easy to work around, with cloud saves?) — I'm more worried about someone hijacking a popular game to distribute malware on a large scale.

In Android, the system essentially launches each app as a different user

That's neat! I should look into Android security more. As you say though, one-user-per-game on Linux hardly seems practical (except if maybe those were temporary users, deleted after the game shuts down..)

one way to solve this would be to only make the root directory of the "current game" traversable.

That's essentially what the OSX implementation does (so it's stricter than the Windows/Linux solutions), but it's easy to relax later.

@seanmakesgames
Copy link

Here let me throw some more wrenches in the machinery:

How does this handle Unity3D game save data (which saves to %appdata% on windows and ~/.config on mac)? Will it go into the launch user's instances of that stuff? How does the main user access that for troubleshooting? How does it work with a solution like per-session users?

@fasterthanlime
Copy link
Collaborator Author

How does this handle Unity3D game save data (which saves to %appdata% on windows and ~/.config on mac)? Will it go into the launch user's instances of that stuff? How does the main user access that for troubleshooting? How does it work with a solution like per-session users?

I'm going to document all of this in time (and for a period of time, the sandbox will be opt-in, so players and developers have time to poke their various games with it and see how it reacts - I'll definitely make sure to be responsive in helping people get their stuff working in there).

To address the actual question:

  • On Mac, the sandbox allows writing to ~/Library/Application Data/ (it just blacklists a few itch directories), and it's not even running as another user, so, no change there
  • On Windows & Linux, there's a few ways to go about it - by default, it would go to C:\Users\itch-player\AppData and /home/itch-player/.config, but nothing prevents us from creating folders like C:\Users\sean\AppData\itch-data and /home/sean/.config/itch-data which would be writable by the itch-player user, and that environment variables like $USER, $HOME, or $XDG_CONFIG_PATH / $XDG_DATA_PATH would point to.

Failing all this, game manifests (cf. #92) could allow specifying a list of directories which the games needs to be writable - and the user would have to agree to that (cf. Android permission model) - but I really would rather have games be well-behaved and follow the relevant environment variables.

@fasterthanlime
Copy link
Collaborator Author

(For the record - I don't expect this feature to take a lot of time. Most of the research is done, and the implementation is pretty clear/straight-forward.)

@seanmakesgames
Copy link

Excellent. These all sound low-impact to the development of the games. :)
All of this is good news. The decision for opt-in is a good one: this will spread out the work over a period of time. (I think most devs will want to get on board with that, given they don't want to be 'the app that was the problem')

@fasterthanlime
Copy link
Collaborator Author

These all sound low-impact to the development of the games. :)

That's the goal — kind of the whole approach behind the app. I want "most games" to work out of the box without being modified, but if you're the kind of gamedev that does funky stuff then it should be possible, by reading the integration docs and/or instructing the app on how to behave with your particular game.

Also, the 'sandbox' vocabulary reminds many devs of stuff like the Mac App Store which is very very restrictive (it uses the same sandboxing facilities as far as I know — just with a very severe policy), so I want to avoid using 'sandbox' publicly to talk about this feature. Not sure "Isolate apps" is the best name for it, but.. that's what it does!

@seanmakesgames
Copy link

seanmakesgames commented Jun 8, 2016

Maybe call it 'secure' apps. Security is something that computer users like. ;)

@quyse
Copy link
Contributor

quyse commented Jun 8, 2016

Maybe call it 'secure' apps

I don't think 'secure' term can be used here. Limiting filesystem access for games is a great feature, it's worth doing even just to prevent accidental damage to user's files (i.e. because of a bug in a game). But I would say one of the biggest security concerns is an access to 3D features. Given the current state (complexity, quality) of graphics stacks, no way you can say that the app is secure while it has access to graphics. For example, the up-to-date AMD graphics driver on my Windows 10 machine crashes if I simply forgot to set vertex and pixel shader and try to draw a primitive via DirectX 11.

You can recall the whole story about security of WebGL, when even within such a highly controlled environment as WebGL multiple vulnerabilities have been found, from denial of service to stealing screenshots of other windows in the system. And native code has full access to the whole giant DirectX/OpenGL API to play with, not to mention poorly documented vendor-specific extensions, backed by crazily complicated software running in ring 0. I think currently it's impossible to give even smallest technological guarantees about security with attack surface like this. All in all you need to trust the author anyway if you run software from them :)

@fasterthanlime
Copy link
Collaborator Author

I think @quyse summed up how I feel about the term "secure" better than I could! I wouldn't want to give a sense of false security — the measures discussed here are supposed to mitigate the threat.

The attack scenario I'm trying to mitigate is the following:

  • Foo is a popular game developed by Alice
  • Alice uses her personal computer both to upload new versions of foo, and play other games
  • Alice is active on social media / easy to interact with
  • Trudy reaches out & asks Alice what she thinks of her new game, Bar.
  • Alice installs and runs Bar via itch, plays around, responds to Trudy's tweet
  • Bar actually stole credentials & sent them home
  • Trudy uses stolen credentials to push a slightly modified version of Foo containing malicious code
  • Foo is seamlessly updated to the malicious version and the malicious code runs on many machines

There's several other measures that could mitigate such an attack, like:

  • E-mail confirmation (opt-out) after a push (to potentially raise the alarm to a developer that something was pushed that they didn't approve of)
  • Better tracking of who did what & where (like the Github security history or Google's Security checkup — lots of quality prior art here)
  • Additional guards when, for example, an API key is used from a new IP address (this shouldn't be too annoying — worst case scenario, the first CI build fails for new users & they have to click a link in an e-mail to whitelist the IP)

TL;DR developers of popular games are good targets and so they need good protection. (How big of a mess could you do by grepping for "steamcmd +login" in all .bat files? Who says one of the many games on Steam doesn't do that? etc.)

@quyse
Copy link
Contributor

quyse commented Jun 8, 2016

@fasterthanlime Oh, surely attack against developer is really worth thinking about too. I can argue though that responsible developer should not run games or any other untrusted software on the developer machine :)

In addition to the good measures you've mentioned I have the following simple ones in mind:

  • access levels or sets of permissions per itch.io API key. E.g. an API key generated by itch app would allow you to authenticate and download purchased games, but not to upload builds - you'll need to generate a separate API key with special upload permission, which you can be more careful of.
  • optional encryption of API key with password, like every time you want to upload a build, you'll have to enter a password, similar to how ssh/pgp works. For developers who doesn't use CI and doesn't mind to upload every build manually it could really improve security. And those who do use CI probably already have building infrastructure separated from gaming machine.

@fasterthanlime
Copy link
Collaborator Author

access levels or sets of permissions per itch.io API key. E.g. an API key generated by itch app would allow you to authenticate and download purchased games, but not to upload builds - you'll need to generate a separate API key with special upload permission, which you can be more careful of.

All API keys are already scoped, and the app API key can definitely not upload builds. However, if we eventually do #672, then it'll be one scarily powerful API key (some parts of the website are behind 'sudo mode' which requires you to enter your password a-la github for 30 minutes of access).

Speaking of #672, originally I thought the API key would be "transformed" into a web session whenever the app detects that you're disconnected, but in fact, I'm thinking it would be better to do it like this:

  • Change the /login endpoint to return both the API key (persistent) and temporary web credentials that the app can use in a webview to auto login (think 'Slack magic sign-in links'). It would expire ~quickly, may be IP-bound?
  • Have the app use those right after login. It'll set cookies in the dedicated electron web session that won't expire for a while.
  • The 'isolate apps' feature above also mitigates attempts to steal cookies

(Note that HTML5 games are launched in a separate web session that doesn't share cookies with the itch.io website)

@Geal
Copy link

Geal commented Jun 9, 2016

A few thoughts on these:
On linux, stuff like cgroups and seccomp could help.
On Windows, it might be possible to execute the app in another desktop (with CreateDesktop, etc), which is essentially what Chrome's sandbox does (with other tricks). This will prevent sending messages to other windows, access to the clipboard, etc.
Also, keep in mind that GPU access is often a pretty big flaw and the cause of many sandbox escapes.

@fasterthanlime
Copy link
Collaborator Author

@greut I wasn't able to make your sudoers.d example work verbatim, maybe it was obvious that it needed modification? This one seems to work on Debian:

ALL ALL=(itch-player) NOPASSWD: ALL

It allows all users to run any command as itch-player without entering a password. Since itch is installed system-wide by the deb & rpm packages, this seems like the most reasonable solution?

(Remember: we're not protecting access to the itch-player account, we're restricting what the itch-player account can do).

@fasterthanlime
Copy link
Collaborator Author

Hit a roadblock on Linux, described here: http://rg3.name/201601171019.html

TL;DR by default, pulseaudio will forbid other users from connecting to it, so, the itch-player user can't play any sounds.

@fasterthanlime
Copy link
Collaborator Author

On Linux, it looks like firejail might be a reasonable alternative to "running as a separate user" (and more flexible too). It resembles OSX's sandbox-exec more.

Opened an issue upstream so that we canship our own version of firejail: netblue30/firejail#567 (the plan is for me to have an automated way to compile+deploy binaries of firejail to an ibrew repo)

@greut
Copy link

greut commented Jun 12, 2016

I've used it on Debian Jessie: http://askubuntu.com/a/159009

@greut
Copy link

greut commented Jun 16, 2016

A similar project to firejail: bubblewrap

Firejail knows about Pulseaudio, whereas bubblewrap does not.

Not good enough, probably.

@fasterthanlime
Copy link
Collaborator Author

@greut yup, unfortunately without suid/root there's not much sandboxes can do about things like PulseAudio which default to a system-wide daemon

@fasterthanlime
Copy link
Collaborator Author

Shipped in v18.0.0!

@magcius
Copy link

magcius commented Jul 2, 2016

Unfortunately, even with Firejail, as long as it uses X11, I, a games developer, can still ship a keylogger using XRECORD / XTEST. Feel free to try my keylogging application under it: https://github.com/magcius/keylog

Not to mention that if you run an NVIDIA GPU, the ioctl's I get on the /dev/nvidia device nodes allow me to break out pretty easily.

As for PulseAudio / bwrap, the teams are working on using memfd to share buffers. Until then, you can turn off shm, similar to what flatpak does:

https://github.com/flatpak/flatpak/blob/master/common/flatpak-run.c#L1501

@fasterthanlime
Copy link
Collaborator Author

Unfortunately, even with Firejail, as long as it uses X11, I, a games developer, can still ship a keylogger using XRECORD / XTEST. Feel free to try my keylogging application under it: https://github.com/magcius/keylog

Preventing key logging is beyond the current scope of the sandbox, but.. you might want to read up on firejail's X11 sandboxing (I think it uses Xephyr?) - it's not enabled in itch by default, but worth exploring if the additional dependencies aren't too much hassle.

I don't believe anything can be done about nVidia proprietary drivers, and for PulseAudio, I'm willing to wait until memfd becomes more mainstream (from what I gather, using memfd will be more secure than their previous way to do shm read/writes?)

At any rate, I'm definitely willing to keep improving the sandbox on all three platforms, and additional research is more than welcome. I would, however, like to avoid making it impractical to the point where "turning it on by default" is no longer a viable or user-friendly option. Right now, I still have to meet a game that fails to run in the current sandbox, and I like that!

@aaronfranke
Copy link

aaronfranke commented Jan 10, 2018

What is the purpose of .itch/isolate-app.profile? It auto-generates if I opt an app into the sandbox.

Is there any reason I would need to adjust the contents of this file?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
security Keep the baddies out
Projects
None yet
Development

No branches or pull requests

9 participants