To Kill -9 a Drone, Part 1

This post first appeared on the Big Nerd Ranch blog.

TL;DR: JSConf 2015 was awesome, and you can open a shell to the Parrot Rolling Spider’s Linux innards with screen /dev/tty.usbmodem…

May is beach month. Every year, I head to the Sunshine State for a fair dose of UV rays to counteract an epidemic skin disease (the treatment usually involves sunburn). Afternoon swims are among the most palatable treatment options, although poolside activities often interrupt it. It takes a certain amount of agility to dodge incoming gulls, beach balls and Node.js-controlled boats.

But contrary to my family’s opinion, I’m not out on vacation. This, in a nutshell, is JSConf: the premier JavaScript conference for nerds in search of web expertise, hardware hackery and East Coast sunlight.

Omni Amelia Island Resort

This year marks my second visit to JSConf’s paradisiacal backdrop on Amelia Island, and is particularly memorable—the talks demoed unusual applications and dazzled the imagination. I also gave my first JSConf talk on replacing native local variables with prototypes.

But I think everyone would agree: the swag item this year blows all the t-shirts and branded beach balls out of the [beach] water.

So. Many. Drones.

I thought the twenty or so AR.Drone quadcopters at last year’s NodeCopter event was unnerving. This year, the conference was swarmed by 700 Parrot Rolling Spider quadcopters.

Parrot Rolling Spider Mini-drone

Despite the drone’s apocalyptic appearance, the human finger inflicts more damage on the tiny plastic props than it does in return. But at 1400 LED eyes and 2800 props strong, the same cannot be said for terrorized house pets and seagulls.

Unlike their bigger brothers, the mini-drones are remote-controlled over Bluetooth Low Energy. So anywhere else, I’d pilot my drone from the FreeFlight mobile app. But JSConf is not just anywhere else. At JSConf, anything that can be, must be controlled by JavaScript.

Thanks to Chris Williams’s pre-conference homework, I was able to pilot my drone from my laptop with vim-style controls and an Xbox 360 controller. That’s pretty awesome, but a little boring, considering we did that last year.

I think my four-winged friend can do so much more: I want to run my own software directly on the drone to make something truly autonomous! I figured there would be docs and posts detailing how this could be done. However.

Eerie silence…

Serial Obsessions

At Georgia Tech, the CS program had a minor obsession with the original AR.Drone, so I've worked with it on a few occasions. Interestingly, it ran Linux, so I suspected that the Rolling Spider also runs Linux. If that was the case, I might be able to open a terminal and peek into the drone’s guts!

With the guidance of my proc killin’ colleague Steve Sparks, we took a historical detour to reminisce about the days of 56k dial-up modems. Coincidentally, modems made an appearance at JSConf, so I had some background.

In the distant past, operators would relay text over telephone lines with keyboards. Similar to dial-up modems, different keys would be converted to a 5-bit code called Baudot code and transmitted over wire. Baudot code was later standardized as ITA2, the predecessor to 7-bit ASCII. The Teletype Writer, as it was called, was later modified for communicating with computer terminals. Nowadays, most Linux devices listen for serial connections (directly through COM, or emulated over USB) and communicate to TTY (Teletype) sockets.

On UNIX machines, TTY devices mount under /dev/tty*. Plugging in my drone over USB, two new entries show up:

$ ls -1 /dev
...
/dev/cu.usbmodem1d113
...
/dev/tty.usbmodem1d113
...

The drone exposes a TTY socket over USB. This is thanks to the getty utility running on the drone, which listens for incoming connections and forwards traffic to the machine’s virtual console.

If the drone is listening, my laptop needs to request and display the login shell. Like yesteryear’s kitchen appliances, the venerable screen terminal emulator can do anything: it even knows how to communicate with a TTY device over serial ports:

$ screen /dev/tty.usbmodem1d113

And I’m in!

BusyBox v1.20.2 (2015-03-06 17:53:39 CET) built-in shell (ash)
Enter 'help' for a list of built-in commands.

#

It doesn’t require a username and password, so it’s probably running root in single-user mode:

# whoami
/bin/sh: whoami: not found

Wow, seems a bit short on conveniences. Let’s try:

# echo $USER
root

That's it! One slight problem though: the drone disconnects after 60 seconds. It’s exasperating to explore the drone’s filesystem one minute at a time, so maybe it’s time for a different approach.

Looking for Clues

While upgrading my drone, I peruse the mysterious rollingspider_update.plf file, which presumably wraps the core firmware update. Since the drone is Linux based, there should be several shell scripts scattered in the update file that could hint at turning off the auto-sleep. Unfortunately, none of the open source AR.Drone PLF extractors work with the Rolling Spider variant.

Time to analyze the update myself. Maybe the update is just a .tar.gz with a different file extension:

$ file rollingspider_update.plf
rollingspider_update.plf: data

Nope. Let’s try strings rollingspider_update.plf, which finds plain text sequences terminated by the NUL character (typical in binaries).

$ strings rollingspider_update.plf
[gobbledygook and  ༼ ༎ຶ ෴ ༎ຶ༽]

Sigh; a few readable bits turn up, but most of the file looks like compressed gobbledygook. strings doesn’t know how to extract compressed strings, but Binwalk does. Binwalk analyzes binary files and extracts resources, like images and text, into their respective files by searching for tell-tale signatures.

$ binwalk --extract rollingspider_update.plf

Binwalk spits out a directory of arbitrarily named files, most of which are binaries.

$ ls -1 _rollingspider_update.plf.extracted
105F5E.zlib
107CC1.zlib
10865F.zlib
10D400.zlib
1134B1.zlib
114918.zlib
...
525E34
529C28
52A63B.zlib
52A761.zlib
52ACE.zlib
...

However, a fair number of files without the .zlib extension are scripts, so I explore all the files starting with the #!/bin/sh shebang. One in particular stands out:

$ cat 43DDA4
etc/init.d/rcS[gobbledygook]#!/bin/sh

# IP_ADDR - this target IP address using CIDR notation:
# <target-ip>/<target-bitmask>
#
# For example:

echo init started...

source /bin/delos_shell.sh

...

echo "Launching Dragon" | logger -s -t "rcS" -p user.info
DragonStarter.sh -out2null &

# Start the FSM managing USB Modes
(delos_monitor_vbus_script.sh)&

echo end init...

Looks like the /etc/init.d/rcS script. On a Linux system, rcS is run after the kernel has booted into single-user mode: it typically initializes some services and mounts the filesystem before kicking off the main program (e.g., the piloting software). The Rolling Spider happens to start up the getty program (which allows us to shell in), telnetd and BLEproxy in rcS. More on the BLEproxy later…

Wakey Wakey, Spidey

After digging through the update file, I’m ready to double down on the 60-second time limit. On a Linux device, “sleeping” likely means the system is shutting down entirely. So if it shuts down, maybe we can search the extracted files for scripts that have the shebang and mention shutdown:

$ comm -12 <(ag -l --search-binary shutdown) <(ag -l --search-binary '#!/bin/sh')
...
7B6170
...

$ head -n1 7B6170
bin/device_monitoring.sh[gobbledygook]#!/bin/sh

Sure enough, one of the scripts, /bin/device_monitoring.sh, appears to track device state (flying, connected over USB, etc.) and notes when 60 seconds of inactivity have passed. The bottom of the script is especially pertinent:

if [ ! -f /tmp/.bleproxy.ftpinprogress -a ! -f /tmp/.shell.userconnected ]; then
  /bin/delos_shutdown.sh
fi

if [ -f /tmp/.bleproxy.ftpinprogress ]; then
  (/bin/device_monitoring.sh)&
fi

It looks like shutdown gets called after 60 seconds, unless /tmp/.bleproxy.ftpinprogress or /tmp/.shell.userconnected exist on the filesystem. So, let’s try logging back into the drone and run:

# touch /tmp/.shell.userconnected

Success! Now the drone will stay on so we can explore indefinitely. It’s a bit inconvenient to run this every time we connect to our drone. It’s also irritating to run screen in the terminal since we lose our nice scrollback, but we can remedy both issues.

Most terminal emulators let you specify “Profiles,” so let’s make one for the drone. I use iTerm2, but the standard terminal bundled with OS X supports profiles as well.

In your preferences, create a new Profile (I named mine “Drone”) and override the login shell. By default, this will be your system’s default shell (like Bash or ZSH), but you can specify screen instead. screen normally connects to the computer’s virtual terminal, but we can pass in our drone’s TTY instead.

Custom Drone Profile in iTerm2

To connect to the drone now, I can open the “Drone” profile and enjoy native scrollback controls. Finally, I want to run touch /tmp/.shell.userconnected as soon as the shell is up, so add that to “Send text at start.”

Now it couldn’t be more convenient to turn those fearsome red eyes to a more interesting orange:

# /bin/set_led_orange_both.sh

Next time…

This isn’t the entire story. In reality, I didn’t figure out the easy-peasy USB method until after trying to connect via Bluetooth. In my next post, we’ll take a detour into virtual machines and the Linux Bluetooth stack for more interesting ways to connect to and control embedded Linux devices.

Jonathan Martin

Jonathan Martin

Globe-trotting web developer, instructor, international speaker and fine art landscape photographer from Atlanta, GA.

Read More