Xen - a backend/frontend driver example

(by )

Recently I began working on my master thesis. For this I have to get familiar with the Xen hypervisor and its implementation of drivers. As the documentation on its implementation is quite sparse I want to write down some of my findings, so others don’t have to re-read and re-learn everything. In this post I’ll focus on how to get a minimal driver in a paravirtualized VM running. Following posts will then focus on how to do communication through event channels and shared memory These are all things I need for the project I am working on, so I need to figure out how this works anyway.

Background

The Xen hypervisor is only a minimal hypervisor implementation, which is booted and then boots a special Linux machine, the so-called dom0. This dom0 is most often just a regular Linux distribution such as Ubuntu. Using Xen-specific tools it is then possible to launch additional virtual machines (VMs). These are called domU. In the default case, dom0 is responsible to acutally talk to the hardware attached to a machine, such as hard disks and the network card. However, VMs of course also need some way to store data or generate network traffic. In Xen this is handled by virtual devices attached to the domU. Generic drivers then proxy data that should be written to disk or network packets to send out through the dom0 to the actual device.

These drivers follow a split-driver model, where one part of the driver, the backend, resides in the dom0 and the other half, the frontend, is a module in the domU machine. Both parts can be implemented as kernel modules and be loaded dynamically.

What’s not documented as clearly as it should be: Activation of the virtual device and thus invoking the right methods of the kernel module is done by writing data to the XenStore. For actual hardware this is already handled automatically. For your own custom virtual device this can be done manually.

A minimal driver

Our driver won’t do anything useful besides saying “Hello” and showing a message when it is activated. The boilderplate for this example is quite huge, the full code can also be found in the xen-split-driver-example repository.

I assume you already have a Xen host, you are connected to the dom0 and have at least one domU running.

The frontend driver resides in mydevicefront.c:

#include <linux/module.h>  /* Needed by all modules */
#include <linux/kernel.h>  /* Needed for KERN_ALERT */

#include <xen/xen.h>       /* We are doing something with Xen */
#include <xen/xenbus.h>

// The function is called on activation of the device
static int mydevicefront_probe(struct xenbus_device *dev,
              const struct xenbus_device_id *id)
{
	printk(KERN_NOTICE "Probe called. We are good to go.\n");
	return 0;
}

// This defines the name of the devices the driver reacts to
static const struct xenbus_device_id mydevicefront_ids[] = {
	{ "mydevice"  },
	{ ""  }
};

// We set up the callback functions
static struct xenbus_driver mydevicefront_driver = {
	.ids  = mydevicefront_ids,
	.probe = mydevicefront_probe,
};

// On loading this kernel module, we register as a frontend driver
static int __init mydevice_init(void)
{
	printk(KERN_NOTICE "Hello World!\n");

	return xenbus_register_frontend(&mydevicefront_driver);
}
module_init(mydevice_init);

// ...and on unload we unregister
static void __exit mydevice_exit(void)
{
	xenbus_unregister_driver(&mydevicefront_driver);
	printk(KERN_ALERT "Goodbye world.\n");
}
module_exit(mydevice_exit);

MODULE_LICENSE("GPL");
MODULE_ALIAS("xen:mydevice");

The backend driver is very similar and resides in mydeviceback.c:

#include <linux/module.h>  /* Needed by all modules */
#include <linux/kernel.h>  /* Needed for KERN_ALERT */

#include <xen/xen.h>       /* We are doing something with Xen */
#include <xen/xenbus.h>

// The function is called on activation of the device
static int mydeviceback_probe(struct xenbus_device *dev,
			const struct xenbus_device_id *id)
{
	printk(KERN_NOTICE "Probe called. We are good to go.\n");
	return 0;
}

// This defines the name of the devices the driver reacts to
static const struct xenbus_device_id mydeviceback_ids[] = {
	{ "mydevice" },
	{ "" }
};

// We set up the callback functions
static struct xenbus_driver mydeviceback_driver = {
	.ids  = mydeviceback_ids,
	.probe = mydeviceback_probe,
};

// On loading this kernel module, we register as a frontend driver
static int __init mydeviceback_init(void)
{
	printk(KERN_NOTICE "Hello World!\n");

	return xenbus_register_backend(&mydeviceback_driver);
}
module_init(mydeviceback_init);

// ...and on unload we unregister
static void __exit mydeviceback_exit(void)
{
	xenbus_unregister_driver(&mydeviceback_driver);
	printk(KERN_ALERT "Goodbye world.\n");
}
module_exit(mydeviceback_exit);

MODULE_LICENSE("GPL");
MODULE_ALIAS("xen-backend:mydevice");

To compile each module indivudally, put them in their own directory and add a Makefile per module:

obj-m += mydevicefront.o

all:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

Change the first line to obj-m += mydeviceback.o for the backend driver.
You can then compile each module on their host and will get a mydeviceback.ko and mydevicefront.ko.

Next, you need to load the modules. In the dom0:

insmod mydeviceback.ko

In the domU:

insmod mydevicefront.ko

Check with dmesg that on both sides you get the “Hello World”.

Activation of the driver requires to add a virtual device to the Xenstore. I wrote a small script, activate.sh to do that.

#!/bin/bash

DOMU_ID=$1

if [ -z "$DOMU_ID"   ]; then
  echo "Usage: $0 [domU ID]]"
  echo
  echo "Connects the new device, with dom0 as backend, domU as frontend"
  exit 1
fi

DEVICE=mydevice
DOMU_KEY=/local/domain/$DOMU_ID/device/$DEVICE/0
DOM0_KEY=/local/domain/0/backend/$DEVICE/$DOMU_ID/0

# Tell the domU about the new device and its backend
xenstore-write $DOMU_KEY/backend-id 0
xenstore-write $DOMU_KEY/backend "/local/domain/0/backend/$DEVICE/$DOMU_ID/0"

# Tell the dom0 about the new device and its frontend
xenstore-write $DOM0_KEY/frontend-id $DOMU_ID
xenstore-write $DOM0_KEY/frontend "/local/domain/$DOMU_ID/device/$DEVICE/0"

# Make sure the domU can read the dom0 data
xenstore-chmod $DOM0_KEY r

# Activate the device, dom0 needs to be activated last
xenstore-write $DOMU_KEY/state 1
xenstore-write $DOM0_KEY/state 1

This adds 3 paths per domain, setting up the virtual device and thus activating the driver. Once you executed that, you again check dmesg. You should now see the Probe called message.

The full code can be found in the example repository.

novemb.rs Code Sprint Weekend 2016 - Retrospective

(by )

This post is a tiny bit late, but better late than never.

So on 19th and 20th of November, just over a week ago, we had the very first novemb.rs Code Sprint. In 10 locations in Europe and the US as well as online, people gathered to hack on projects, start new ones or just to learn Rust. Bringing people together is one goal of the Rust community and coding, learning and having fun together is a lot of fun as well.

novemb.rs @ C4

We opened doors at Chaos Computer Club Cologne

I was part of the novemb.rs Event in Cologne. On both days about a dozen people showed up, from noon to late in the evening.

In Cologne, we had several different projects and ideas being worked on:

Thanks to our attendees and thanks to my co-organizers Colin, Flo & Pascal. And another big thanks to Mozilla for sponsoring the pizza and the C4 for offering the space.

Things that worked well

Things that we should improve

Rust @ Whiteboard

Coding on the whiteboard (only half of the attendees in the picture)

Try again?

Definitely! Given that the overall organization effort is low I’d like to make this a more regular thing. With the experience from this year we have enough points to improve and we can plan this in advance. Plus, we already have the domain anyway ;)

Until then, there are of course other opportunities to get in contact with fellow Rustaceans. We have a monthly meetup in Cologne, with a Christmas-themed impl Glühwein for RustCologne happening next week. Feel free to join us on the Weihnachtsmarkt or in January at another more regular meetup. If you are not from the Rhein area, take a look if there’s a Rust User Group near you.

Rust

Signs showed the way

Signify - Ed25519 signatures for your files (in Rust)

(by )

From time to time I try to write a piece of code or port some existing library or application just for fun. So a while back in June I had some free time again and I came across signify. I ported it to rust: signify-rs

signify is a small command line utility to create Ed25519 signatures of files. It was developed to cryptographically sign and verify OpenBSD releases. Read “Securing OpenBSD From Us To You” for more details.

Now all you need to create signatures and verify them is a private & a public key. Both parts are super short, so it is no problem to embed or print them. This is what a public key would look like:

RWR/JMX+u3pyzGSyTSnOFINVcHJycZE/o6UTUshxvpcp6S4annmJK4DB

The corresponding private key is this:

RWRCSwAAAAASfh0v1XJS4FYg59ntf4d7zYS9GR848h1/JMX+u3pyzIFNjvCMxLUgurelzAWTCSd9y6ghUcbcPVMuwnlDJy4WZLJNKc4Ug1VwcnJxkT+jpRNSyHG+lynpLhqeeYkrgME=

(Warning: Do NOT use above keys for anything! I included both for demonstration only)

signify will add an additional comment to the key files, but they are not used for any verification (besides making sure they are actually in the file).

Whereas pure Ed25519 keys are just 32 bytes, above keys already include some additional information used by signify to create and verify signatures. The private key can also be protected by a passphrase.

When I started porting this small application I knew nothing about Ed25519 or signify. I more or less translated the existing C code into Rust. Back then, I used rust-crypto, a pure Rust implementation various common cryptographic algorithms. It provided all I needed: Ed25519 key generation, signing & verification and bcrypt for the passphrase handling. In just one day I had a working application and less than 2 weeks later I also implemented proper passphrase-protection.

In August then the most promising Rust crypto library, *ring*, was released on crates.io as well (before that it could only be used as a git dependency). I used *ring* before for nobsign and Brian Smith, the author of *ring*, already helped out with some code review & helping me use the API properly.
So I was not too surprised when Brian reached out to me asking if I would be willing to port signify-rs over to *ring* as well.

I was (however, it was shortly before RustFest, so I couldn’t dedicate much time to it).

I took a look at the *ring* documentation and immediately realised I had a completely wrong understanding of Ed25519. Whereas in signify the public key is stored in 32 byte and the private key is stored in 64 byte, *ring* had both keys as only 32 byte long. With feedback from Brian I realised that the longer private key as used in signify is actually just the 32-byte public key concatenated to the (real) 32-byte private key, resulting in 64 byte total.

Equipped with this information (and after the first RustFest day was over), it was easy to port over signify-rs to *ring*.

signify-rs still depends on rust-crypto though, as it provides the necessary bcrypt_pbkdf for encrypting the private key with a user-chosen passphrase. *ring* does not provide bcrypt and probably won’t do so anytime soon. If anyone wants to implement a really good bcrypt crate, please contact me or Brian for feedback.

Use signify-rs

First you need to install it, do so with cargo:

cargo install signify

Generate a key pair:

signify -G -p public-key -s secret-key

This will ask you for a passphrase to protect the secret key. Remember that. Now you can sign a file:

signify -S -s secret-key -m README.md

This will create README.md.sig containing the signature. To verify it:

signify -V -p public-key -m README.md

If it prints Signature Verified it went well. Otherwise it will show an error.

A signature

This is the signature using above private key on the README.md:

untrusted comment: signature from signify secret key RWR/JMX+u3pyzIDv+Gt4JwMbWsb+dt0R/9tYDEjVw7zmBQoQR06Pcd2yr03XqvTSqaJBTbUhm74iUxB98BQVAZemq692g5Xv0gs=

If you put that signature in a file, put the public key from above into another, you can verify it!

Future plans

I still have todos left for this project. First I want this to be fully compatbile with the original implemenation. The original implementation can embed signatures into the signed file and also verify an embedded signature. I want to add that. I also want to distribute pre-compiled binaries for various platforms (hello, rust-everywhere) and provide proper Ed25519 signatures on all those releases.

If you want to help with any of that, jump over to the GitHub repository and start hacking.

Rust from the Back to the Front (Rust Sthlm)

(by )

Rust on the Web

Last monday I attended the Rust Sthlm Meetup and gave a talk about using Rust for web development. About 60 people attended, had pizza and listened to the two talks of the evening.

Meetup

I started off with my talk Rust from the Back to the Front, giving an overview of the ecosystem around all things related to web programming in Rust. This was an updated talk of the one I gave in Budapest last year (video online). I had some technical difficulties this time in the beginning (yeah, computers…), but otherwise the talk went well. People showed interest in the presented topics. Sadly I only briefly touched the new way of doing asynchronous I/O using futures and tokio. I definitely need to look deeper into this topic, as I think it can bring huge improvements to existing web frameworks and libraries as well. This has to wait a bit though, as I will first dive deeper into Emscripten (and present that next week in Cologne and in Pittsburgh in October). My slides are online and I will try to collect more resources in a Gist.

Rust and openSUSE

The second talk that evening was by Kristoffer Grönlund, giving us a quick introduction to some of Rust’s features, followed by an overview of his work trying to get Rust into the openSUSE package repositories. Turns out it is not that easy, especially if everything has to be built from source and offline, but at least there are some improvements that might help make this easier. His slides are online as well.

Even after the talks some of the people stuck around and we discussed several more things around Rust, how it is still evolving, fast moving and a bit unstable from time to time.

All in all I had a great time, talked to a number of people about differen topics and I hope I could convince some to actually try Rust. With such a large and interested tech community in Stockholm, I’m sure the Meetup will live on.

Longboarding: Vennbahn

(by )

Today, right after finishing my only lecture of the day, I rented a longboard at a local skate shop and then took the bus out of the city. I went out to Kornelimünster, a small district of Aachen, about 10 km outside of the city.

In the last days it rained half of the day, but today it’s sunny and really warm. The route goes mostly downhill from Kornelimünster, so I did not need much pushing and could just let it roll.

I collected the route with an app. The results: 10,9 km in 53 minutes. Top speed: 31,5 km/h. 12,4 km/h on average.

I was much quicker than I thought, so I got some ice cream in the city of Aachen before heading home.

The route on a map (available in a Gist):