What a week. Progress has felt a bit slow, but the work has been
consistently interesting, and there have been some exciting developments
in the ecosystem.
Last week I'd posted the patches required to get all of Spectrum working
with a more up-to-date Nixpkgs. After last week's email, Cole reviewed
the patch set, so I applied it, and merged the nixpkgs-update branch
into master, so now Spectrum is using a reasonably up-to-date Nixpkgs
for the first time in a long time.
I also said
> Once that's done, it's time for another chromiumOSPackages upgrade, but
> that should be pretty easy this time because we're only one version behind.
Alas, it's never that simple.
Firstly, the chromiumOSPackages update script broke, because the
information about the currently released Chromium OS build seems to have
gone missing. Google is apparently serving build number 13982, but
their published build metadata includes builds 13981 and 13983, but
not 13982. This means it's not possible for me to know what Git
revisions are used in the currently released Chromium OS. Assuming this
is just a one time thing, I hacked the update script to just look at the
previous build, but we should keep an eye on this. If it ever happens
again we should probably implement some sort of mitigation in the update
Once I had new versions of the Chromium OS packages it was time to get
them to build, which was straightforward enough for everything except
crosvm. For Spectrum, we have a patch for crosvm to make it support
VIRTIO_NET_F_MAC, which is a mechanism by which the host system can
indicate to the guest kernel what it should set as the MAC address of a
virtual network device. After the update, this patch no longer applied,
because all of a sudden crosvm has two different virtual network device
This turns out to be because crosvm has implemented vhost-user, a
protocol to allow virtual devices to be implemented outside the VMM
program! This is great news, but it's also surprising. virtiofs was
designed to be implemented with vhost-user, but when crosvm implemented
it a while ago, they became the only implementer to do so in-VMM. It's
great to see them moving in the vhost-user direction, because it makes
it much easier to mix and match virtual device implementation and VMMs.
Most excitingly, I saw a reference to vhost-user-wl, meaning a
standalone implementation of Virtio Wayland. This would allow us to use
Virtio Wayland with other, non-crosvm VMMs, which is great because I
think cloud-hypervisor is probably going to end up being a better fit
for Spectrum, but Virtio Wayland was crosvm's killer app. I'd even
thought about trying to port crosvm's virtio wayland implementation to
vhost-user myself, so it's great to know that when the time comes,
that'll already have been done for me.
While I could have fixed my crosvm patch for all this new virtual
network device code, the introduction of vhost-user support means we
should be able to drop the patch altogether. cloud-hypervisor provides
a vhost-user-net implementation that already supports
VIRTIO_NET_F_MAC, so if we can just get crosvm to talk to
cloud-hypervisor's vhost-user-net implementation we shouldn't have to
carry any patch for this any more.
cloud-hypervisor / rust-vmm
So I started looking at cloud-hypervisor to try to hook this all up, but
it looks like cloud-hypervisor still has some issues where it doesn't
quite follow the vhost-user specification. As I was trying to debug
this, I noticed some UB in rust-vmm (the shared utility code project
for crosvm and its derivatives like cloud-hypervisor and
Being a good citizen, I started working on a fix for this, and then I
encountered some more issues with functions that should have been marked
as unsafe but weren't. So that's going to need to be fixed too.
But the rust-vmm code is otherwise very high quality and easy to work
with, and they're very responsive, so it shouldn't take long to get
these issues fixed. The affected code is fortunately all to do with
communication between vhost-user backends and the VMM, so it's very very
unlikely that it's anything that could be exploited by a guest.
These sorts of problems are exactly the sort of thing that Rust is
supposed to prevent, so it was disappointing to discover these issues.
But on the other hand, Rust made them stand out like sore thumbs to me,
so even though these issues managed to sneak in, there's definitely
still a huge benefit to using Rust for these sorts of programs.
In the next week, I'm hoping to get all the rust-vmm issues I've
discovered fixed, and maybe get cloud-hypervisor's backends to speak
proper vhost-user. I'm getting my second vaccination next week as well
though, so we'll see. I might just end up being sick.
Hi! I've had a busy day today and am pretty tired, so I'm not sure how
coherent my writing is at the moment. But I'd rather get this out on
time, especially since tomorrow is also busy today.
As I said last week, I took some time off this week as a preventative
measure against burnout.
One of my patches was accepted, but another is still waiting. As
I said last week, I have more fixes for rust-vmm planned, but want to
let them catch up with the changes I've already sent upstream first so I
know what base I'm using for the next stuff. I expect the one that's
still waiting to be accepted next week.
Last week, I'd just integrated dm-verity into the Spectrum live image
I've been working on. When it came time to work on the actual root
filesystem, instead of the initramfs, I hit a bit of a brick wall. I
realised that trying to generate a whole operating system image using
Nix was giving me real writers' block. There was too much inbetween me
and how the files ended up on disk, and that meant there was too much
overhead to keep in mind when I was thinking about how things should be
designed and laid out. It might feel like making a Linux root
filesystem should be a solved problem, but Spectrum has a bunch of
special requirements. You might want to do something like start a VM
for each hardware device of a specific type, and that's something that
isn't really addressed by most standard stuff. All this stuff is
definitely solveable, but it requires some experimentation to get right,
and Nix was getting a bit in the way of that.
So I created a new directory, and I wrote a Makefile that builds an
ext4 image, and I just started putting files in an etc/ directory. This
made reasoning about the system way easier, and I was immediately making
Nix is great for building known targets, and for making customisable
systems (there's no way my Makefile-based system would allow the amount
of customisation I'd easily be able to provide with Nix), but for
experimentation, it's a lot nicer to be closer to the end product. So
once I know how all this should look I'll make it Nix-aware.
Currently, I have a root filesystem with a service manager that can
respond to hardware appearing and disappearing. The next (more exciting)
step will be to have it start some VMs, and assign hardware to them
appropriately. I'm looking forward to getting to that next week. An
interesting challenge I'll have to solve will be figuring out simple
categories (e.g. "ethernet device") from the huge amount of very
specific information the kernel provides. I think I might be able
abuse the modules.alias file from the kernel, that defines the mappings
from PCI etc. information to default drivers. Then all I'll have to do
will be to write mappings from default drivers to whatever categories I
come up with, or what VM I want to assign them to, or whatever.
One neat thing I'm using for the first time here is tar2ext4, a
utility program that's part of a larger Microsoft open source project I
don't entirely understand the purpose of. It's really useful for me
it builds ext4 images entirely in userspace, which will be great for
using in Nix derivations where it's not possible to just mount an ext4
image and write directly to it. For previous Spectrum experiments, I'd
always used SquashFS, entirely because I already knew of a tar2sqfs
program that made creating filesystem images really easy. I've added
tar2ext4 to Nixpkgs, which will hopefully help other people who have
similar problems discover it.
While I was working on the root filesystem, I noticed that mount -a,
which mounts all filesystems described in fstab(5), wasn't working.
This turned out to be because of a bug in Musl's implementation of
getmntent(3), a libc function for parsing fstab files.
So I wrote some tests and a fix and sent them to Musl.
Hope that all made sense.
Next week, I'll continue working on Spectrum live, and maybe fix the
next rust-vmm issue I have on my todo list if my final outstanding PR
It's a short update this week, because most of what I did was a
continuation of stuff from last week.
Last week, I mentioned I'd identified some Rust safety issues in
rust-vmm. Most of the patches for these are now up. The first
has been accepted already, and I expect another to be accepted later
today. There's still a UB issue I'm aware of and haven't sent a fix for
yet, because there are a number of ways to fix it and I wanted to get my
other patches in first before I decided how to fix that one.
I deliberately haven't made any progress on using cloud-hypervisor's
vhost-user-net backend with crosvm, which is what got me looking at this
code in the first place. I want to make sure I can work on
rust-vmm-adjacent things at a pace where I don't get overwhelmed with
having to keep track of loads of patches and whether I've got them
upstream yet. So I'll be putting that work on hold until the current
round of patches are upstreamed.
For the past little while, in the time when I wasn't writing regular
updates, I've been working on a live system for testing Spectrum. This
will be especially useful for testing things like GPU support, because I
can just build a live image with everything I might need, plug it into
all the computers I want to test, and have everything be automatic from
there. It will also probably evolve directly into what becomes the
Spectrum base system that we'll hopefully all be running as the host
system on our machines at some point.
I shifted my focus back to this this week because of wanting to not get
ahead of myself with rust-vmm. (I have a funding milestone for GPU
support, so getting that checked off soon would be good.) The main
thing I did this week was integrate dm-verity, which I did mostly for
fun and to satisfy my curiosity.
dm-verity is a Linux mechanism to efficiently ensure that a read-only
filesystem hasn't been tampered with, by constructing a Merkle tree out
of filesystem block hashes, and providing the root hash to the kernel
when the filesystem is mounted. dm-verity is a _great_ fit for Nix,
because we can generate the hashes at the same time as creating the
filesystem image, and then embed the hash into the initramfs we're also
building. Getting this all working took less than a day. The idea is
that (long) in the future, we'll also implement Secure Boot, which will
make sure the kernel and initramfs haven't been tampered with, and
dm-verity will extend that integrity guarantee to the host system's root
filesystem. I recommend reading "Producing a trustworthy x86-based
Linux appliance" by Matthew Garrett for an overview of how this all
dm-verity is something that's particularly exciting to me, because it's
very useful to us, but it's something that's generally used to frustrate
end user attempts to control computers they own. In Spectrum, it's
instead a tool that protects the end user against malicious filesystem
changes, while being almost completely transparent to the user if they
do want to modify their own system.
Protecting against root filesystem tampering (which would require a VM
escape or physical device access) is hardly the biggest priority for
Spectrum, but integrating dm-verity was fun, interesting, and provided
good motivation for working on the live image, which is one of the
highest priority bits of the system. (Because I'm tired of having to
say "you can't" when people ask me how they can try out Spectrum.)
This week, I'm going to take a bit of time off as an anti-burnout
defense, but probably not the whole week. I'll still keep an eye on the
rust-vmm patches throughout this time as well, to make sure they're not
delayed in getting accepted upstream.
Hi, it's been a long time since I've done one of these, but so much
interesting stuff happened this week, and there's been a bit of renewed
interest in the project, that it _really_ needed an update. So here it
is. As always when I'm not keeping up with TWiS, this update is limited
to only things that happened in the last week, because otherwise it
would just be far too long.
A problem I've been thinking about for a long time is Wayland access
control. The Linux desktop ecosystem is moving towards access controls
for most functionality through xdg-desktop-portal (which sadly
doesn't seem to have a website). But it doesn't cover stuff that's part
of the core Wayland protocol, like access to the clipboard. And some
compositors (wlroots-based ones) provide extra Wayland protocols for
things like screenshots. And up to now, Wayland compositors haven't
really done any authorization for these potentially dangerous APIs.
(All of this is only really meaningful for sandboxed applications --
running in Flatpak or a Spectrum VM or something. Linux isn't
really set up to do separation between processes running as the same
user without namespaces.)
So earlier this week, I posted to the Wayland mailing list with an
idea I'd been thinking about for a while, which was to place a proxy
program in front of the Wayland compositor, that would intercept
client->compositor requests and handle access control. I was quickly
convinced that a proxy wasn't a good idea, but there was a lot of
discussion, and it was really helpful to me figuring out what the right
way to do it might be.
There are really two problems to be solved here, one of which I hadn't
even thought much about. The first is securely identifying a Wayland
client. A compositor needs to be able to form the question "Should
client X be able to do this?", and to do that it needs to be able to
identify a client as client X, and know if it tries to interact with
client X later, that it'll be talking to the same client. In a
non-virtualized system, the obvious way to do this would be getting the
pid of the client from the connection socket and then looking it up in
proc(5) to find out executable path, but this approach is fundamentally
The way forward here (and one that would work for Spectrum) appears to
be the proposed Security Contexts protocol, which would allow a
sandbox implementation to provide a security context identifier for a
client before handing off the Wayland connection to the client. Once
the security context had been set up, it wouldn't be allowed to be
modified, so once the sandboxed client was given the connection, it
wouldn't be able to change the security context identifier.
In Spectrum, the security context identifier here would likely be a
unique, user-provided name for the VM, and the security context setup
would be done by the virtio wayland implementation in the VMM.
The second part of this puzzle is how the compositor should decide
whether a client should be allowed to perform a particular operation,
like a paste or going fullscreen (which is risky because it might spoof
There was actually a previous attempt at this a long time ago.
libwsm (short for Wayland Security Module) was a library that
compositors would have integrated to make authorization decisions. But
it wasn't adopted by compositors, and it some things we now know to
be bad ideas, like setting policy based on the executable path. It also
made compositors responsible for any sort of authorization UI. In my
opinion, it's better to have that done by the external piece, so that
compositors have as little work to do as possible and therefore
authorization is implemented as widely as possible.
The compositor could implement an authorization system entirely on its
own, but this would be a lot of code for each compositor to write, and
it would limit the user to whatever permissions system the compositor
came up with, which might not be able to accommodate their needs. (An
example of this would be a Spectrum user that wanted to allow pasting
between two applications, but not allow pasting between either of those
and any other application.)
It could also be implemented by having the compositors integrate with
something like polkit, but compositor authors are reluctant to
integrate directly with a single system like that, and even polkit might
not support everything that would be desirable in an authorization
system. (For example, it might be nice to implement libwsm's concept of
a soft allow, where an action is permitted, but a notification is shown
so the user is aware it's happened.)
So a third solution, suggested by ifreund, a Wayland compositor author,
in the Spectrum IRC channel, would be to have a privileged Wayland
client that the compositor could ask authorization questions to, with a
new protocol. The compositor would know that this particular client
should be privileged because it either wouldn't be in a security
context, or would be given a special security context identifier known
to the compositor ahead of time. Then, implementations of this protocol
could do authorization however they wanted, with the only limitation
being the questions the compositor was programmed to ask them. I think
this is a good way forward, but it'd be important to discuss with more
compositor authors before getting to excited about it.
Next steps from here with Wayland are:
* Figure out what needs to happen to move the security contexts
proposal forward. If it needs an experimental implementation, maybe
we could help with that?
* Inquire about the authorization protocol idea, and see how other
compositor offers would feel about it. If there's a generally
positive reaction, figure out how to move forward with it.
I created a branch in Spectrum's nixpkgs repository for the
long-overdue merge with upstream, did the merge, and posted some
patches to spectrum-devel that fix all the builds that broke as a
result. I've been letting them sit for a few days hoping for a review.
Once that's done, it's time for another chromiumOSPackages upgrade, but
that should be pretty easy this time because we're only one version behind.
Thanks for keeping up with Spectrum. :)