January 2, 2017

Rooting steamlink pt1

This is a first in a multi-part series on digging into the steam link software and hardware. I’m hesitant to call it reverse engineering’ because thankfully, much of the way the steam link works is very open and straightforward on a well defined linux setup which is a very nice change, and there is not much to it for them to want to hide.

Part 1: gaining access

Luckily, as above eluded to, this is very simple and nothing of serious effort is needed to get root on the steam link. Part one will cover how to get root SSH access with instructions for windows users.

A huge thanks goes to Aaron aka mcd1992, he already found out all the hard parts of this in a post a little over a year ago and that is the source of this work, it’s available here. I added a few details that were missing and made sure it worked on latest beta.

The process is dead simple, but there are a few gotchas which can make things unclear, here’s what you need:

  • steam link (duh right?)
  • USB drive of literally any size. I did this with an ancient 2GB drive
  • way to format USB drive to FAT32/exFAT or ext4. These instructions will be for windows. For Linux, I assume you are competent enough to create partitions. ext4 works as well as FAT32 for the USB drive.

Still, with that in mind, it would be fun to look at the internals, and maybe see what we can change.


  1. important: make sure the first partition of your USB drive is FAT32 or ext4. any size will do. If you quickly need to reset a usb stick with a raw image on it, google running DISKPART as admin and doing select disk #’ and then clean.
  2. On your USB stick partition, simple create the following full path file: steamlink/config/system/enable_ssh.txt
  3. Make sure the file is not empty by adding, eg 666’ to the file and saving it. encoding doesn’t appear to matter
  4. Eject your USB stick and plug it into your steam link’s front right USB port. NOT BACK
  5. super important: completely remove power from the steam link and plug it back in. take effect when off, but not unplugged.
  6. once steam link has started up again, go to settings->network and see what the IP is. You should now be able to SSH in. the user is root’ and the password is steamlink’.
  7. if SSH is still not open, connect to a desktop running steam and try again. This got me bad, I had not synced to a new steam install.

RANDOM OPINIONATED SIDENOTE: Open software/hardware setup is always a net benefit from an engineering standpoint. If you’re making consumer electronics, you’ll never lose an average customer when you go out of the way to lockdown your flash chip holding your firmware or such, ignoring proprietary issues. Same goes for disabling an-already-running-linux device from accepting remote logins. Obviously you have to have some degree of control so you can support your device, but it doesn’t hurt to allow technical users fair use. f you feel you would give up an advantage to a competetor, your hardware is probably not very compelling or unique in the first place. Digression over

Now what?

Lets take a look around and get a lay of the land with ps:

1 root       0:00 init
2 root       0:00 [kthreadd]
3 root       0:00 [ksoftirqd/0]
4 root       0:00 [kworker/0:0]
5 root       0:00 [kworker/0:0H]
6 root       0:00 [kworker/u:0]
7 root       0:00 [kworker/u:0H]
8 root       0:00 [khelper]
9 root       0:00 [kworker/u:1]
228 root       0:00 [bdi-default]
230 root       0:00 [kblockd]
241 root       0:00 [khubd]
258 root       0:00 [cfg80211]
274 root       0:00 [rpciod]
293 root       0:00 [khungtaskd]
298 root       0:00 [kswapd0]
343 root       0:00 [fsnotify_mark]
359 root       0:00 [unionfs_siod]
360 root       0:00 [nfsiod]
364 root       0:00 [cifsiod]
375 root       0:00 [crypto]
524 root       0:00 [flush-31:10]
548 root       0:00 [krfcommd]
606 root       0:00 [deferwq]
616 root       0:00 [yaffs-bg-1]
620 root       0:00 /sbin/ueventd
741 root       0:00 [kworker/0:1]
793 root       0:00 sleep 2
794 root       0:00 ps aux
811 root       0:00 [yaffs-bg-1]
842 root       0:00 [scsi_eh_0]
843 root       0:00 [usb-storage]
879 root       0:00 [yaffs-bg-1]
884 root       0:00 [yaffs-bg-1]
948 root       0:00 [loop0]
952 root       0:00 [jbd2/loop0-8]
953 root       0:00 [ext4-dio-unwrit]
969 root       0:00 [kworker/0:1H]
987 root       0:00 [kworker/0:2]
1077 root       0:00 [MOAL_HANG_WORK_]
1078 root       0:00 [MOAL_WORK_QUEUE]
1079 root       0:00 [MOAL_RX_WORK_QU]
1080 root       0:00 [woal_reassoc_se]
1081 root       0:00 [ksdioirqd/mmc0]
1082 root       0:00 [kworker/u:1H]
1133 messageb   0:00 /usr/bin/dbus-daemon --system --fork
1135 root       0:00 dbus-daemon --fork --session --print-address
1154 root       0:02 {wpa_supplicant.} /bin/ash /etc/init.d/wpa_supplicant.sh
1204 root       0:00 [bt_main_service]
1205 root       0:00 wpa_supplicant -B -u -c/tmp/wpa_supplicant.conf -Dnl80211 -imlan0
1207 root       0:00 [hci0]
1212 root       0:00 /usr/libexec/bluetooth/bluetoothd -E
1232 root       0:00 /usr/bin/pulseaudio
1252 root       0:00 /usr/sbin/pacrunner
1271 root       0:00 {connmand.sh} /bin/ash /etc/init.d/connmand.sh
1278 root       0:01 connmand -n --wifi=nl80211
1297 root       0:00 /usr/sbin/sshd
1317 root       0:00 watchdog -t 2 -T 4 /dev/watchdog
1382 root       0:00 [galcore workque]
1383 root       0:00 [galcore daemon ]
1392 root       2:38 ./bin/PE_Single_CPU
1393 root       0:00 {powermanager.sh} /bin/sh ./bin/powermanager.sh
1395 root       0:00 /bin/getty -l /bin/login 0 console
1396 root       0:06 powermanager
1441 root       0:00 {app_run.sh} /bin/sh /home/steam/app_run.sh
1446 root       1:37 shell
1532 root       0:00 sshd: root@pts/0
1548 root       0:00 -sh

As we can see, valve did a great job running only what is absolutely needed. The main area of interest is /etc/init.d/startup folder. You can see how it bootstraps the entire user process and what files it checks for overrides, like we did w/ SSH. If we take a look at /etc/init.d/startup/S30sshd we can see it sets root password in a strange way if needed

# Script to start sshd if desired

if [ -f /mnt/config/system/enable_ssh.txt ]; then
        # Generate ssh keys if necessary
        if [ ! -f /etc/ssh_host_rsa_key ]; then
                ssh-keygen -A

        # Set root password if needed
        if grep -q "root::" /etc/passwd; then
                passwd root <<__EOF__


An odd thing is the password steamlink’ and both steamlink123’ as seen above work. The user interface is bootstrapped by the /home/steam/rc.local file. Looking at this, we now know it’s using a Marvell Berlin SoC, which would be no surprise if you did your homework unlike me

No frills here really

# lsmod
gal3d 150885 2 - Live 0xbf11e000
gfx 5594 0 - Live 0xbf118000
galois_pe 23250 8 - Live 0xbf10d000
bt8xxx 65343 1 - Live 0xbf0f5000
sd8897 465471 1 - Live 0xbf06c000
8897mlan 386305 1 sd8897, Live 0xbf000000 (P)
# cat /home/steam/controller/NOTES.txt

d0g_dongle_steamlink.hex  - Valve dongle firmware for internal dongle
d0g_dongle.hex - Valve dongle firmware for external dongle

steamlink root embedded

Previous post
PL/pgSQL Conway’s game of life I recently started learning the details of PL/pgSQL. It actually started with me wanting to learn Oracle PL/SQL but giving up after looking at
Next post
endless static site fights After a bit of messing around, completely nuking the old site (GH pages Jekyll setup), putting up silly 10mb ascii art index.html files and writing