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

Fix Steam input in unprivileged containers #81

Open
ABeltramo opened this issue Jun 27, 2024 · 2 comments · May be fixed by #88
Open

Fix Steam input in unprivileged containers #81

ABeltramo opened this issue Jun 27, 2024 · 2 comments · May be fixed by #88
Labels
bug Something isn't working enhancement New feature or request

Comments

@ABeltramo
Copy link
Member

Steam input works by creating virtual devices using uinput (similar to how we do it in inputtino). So the first step is obviously to allow the Steam container to access it:

devices = ["/dev/uinput:/dev/uinput"]
env = [
  "PROTON_LOG=1",
  "RUN_GAMESCOPE=true",
  "GOW_REQUIRED_DEVICES=/dev/uinput /dev/input/* /dev/dri/* /dev/nvidia*"
]

When you start a game with steam input enabled the following uevents will be generated:

➜ docker exec -it -u retro WolfSteam_4135727842959053255 udevadm monitor -p
monitor will print the received events for:
UDEV - the event which udev sends out after rule processing
KERNEL - the kernel uevent

KERNEL[13943.544155] add      /devices/virtual/input/input165 (input)
ACTION=add
DEVPATH=/devices/virtual/input/input165
SUBSYSTEM=input
PRODUCT=3/28de/11ff/1
NAME="Microsoft X-Box 360 pad 0"
PROP=0
EV=20000b
KEY=7cdb0000 0 0 0 0 0 0 0 0 0
ABS=3003f
FF=10000 0 0
MODALIAS=input:b0003v28DEp11FFe0001-e0,1,3,15,k130,131,133,134,136,137,13A,13B,13C,13D,13E,ra0,1,2,3,4,5,10,11,mlsf50,w
SEQNUM=23561

KERNEL[13943.544214] add      /devices/virtual/input/input165/event26 (input)
ACTION=add
DEVPATH=/devices/virtual/input/input165/event26
SUBSYSTEM=input
DEVNAME=/dev/input/event26
SEQNUM=23562
MAJOR=13
MINOR=90

KERNEL[13943.544244] add      /devices/virtual/input/input165/js3 (input)
ACTION=add
DEVPATH=/devices/virtual/input/input165/js3
SUBSYSTEM=input
DEVNAME=/dev/input/js3
SEQNUM=23563
MAJOR=13
MINOR=3

As you can see it's missing the corresponding udev events (network isolation for the win); we'll have to pick those kernel events up, mknod the devices and relay the correspondent udev event using fake-udev.

The only bit that I'm not sure is how to avoid mounting other containers devices. Unfortunately kernel events aren't isolated, for example I can see the event for when a device is plugged in the host.. How can we mknod only the devices that are actually generated by this steam instance? Intercept /dev/uinput ioctl calls?

Quick fix

This will break isolation, but for a single user this should work:

[[apps]]
title = "Steam"
start_virtual_compositor = true

[apps.runner]
type = "docker"
name = "WolfSteam"
image = "ghcr.io/games-on-whales/steam:edge"
mounts = ["/dev/input:/dev/input:rw", "/run/udev:/run/udev:ro"]
env = [
  "PROTON_LOG=1",
  "RUN_GAMESCOPE=true",
  "GOW_REQUIRED_DEVICES=/dev/uinput /dev/input/* /dev/dri/* /dev/nvidia*",
]
devices = ["/dev/uinput:/dev/uinput"]
ports = []
base_create_json = """
{
  "HostConfig": {
    "NetworkMode": "host",
    "IpcMode": "host",
    "CapAdd": ["SYS_ADMIN", "SYS_NICE", "SYS_PTRACE", "NET_RAW", "MKNOD", "NET_ADMIN"],
    "SecurityOpt": ["seccomp=unconfined", "apparmor=unconfined"],
    "Ulimits": [{"Name":"nofile", "Hard":10240, "Soft":10240}],
    "Privileged": false,
    "DeviceCgroupRules": ["c 13:* rmw", "c 244:* rmw"]
  }
}
\
"""

And set the env variable WOLF_DOCKER_FAKE_UDEV_PATH="" to disable our fake_udev implementation.

@ABeltramo ABeltramo added bug Something isn't working enhancement New feature or request labels Jun 27, 2024
@Drakulix
Copy link
Contributor

Intercept /dev/uinput ioctl calls?

Yes. A valve engineer confirm to me, that LD_PRELOAD-ing steam to do this should give us all the infos we need.

Basically we should intercept UI_DEV_CREATE and then internally call UI_GET_SYSNAME, matching the name to our container and returning from the intercepted ioctl.

Everything that is not UI_DEV_CREATE we can just passthrough and ignore.

@ABeltramo
Copy link
Member Author

Thank you so much for confirming it! It should be fairly straightforward then, just need to plug together fake-udev and mknod in a simple library that I'll preload.
Damn I wish I could bother a Valve engineer too 😅

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working enhancement New feature or request
Projects
None yet
2 participants