qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* Why QEMU should move from C to Rust (clickbait alert ;))
@ 2020-08-06 10:24 Stefan Hajnoczi
  2020-08-06 11:08 ` Daniel P. Berrangé
  2020-08-06 11:51 ` Sergio Lopez
  0 siblings, 2 replies; 14+ messages in thread
From: Stefan Hajnoczi @ 2020-08-06 10:24 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Maydell, Sergio Lopez, Dave Gilbert, Markus Armbruster,
	Oleinik, Alexander, Paolo Bonzini, Alex Bennée

I just posted this on my blog, but my intention is to continue the
discussion around moving to Rust in the QEMU community. Thoughts about
how to increase safety in QEMU, both for and against moving to Rust
are welcome!

My KVM Forum 2018 presentation titled Security in QEMU: How Virtual
Machines provide Isolation reviewed security bugs in QEMU and found
the most common causes were C programming bugs. This includes buffer
overflows, use-after-free, uninitialized memory, and more. In this
post I will argue for using Rust as a safer language that prevents
these classes of bugs.

In 2018 the choice of a safer language was not clear. C++ offered safe
abstractions without an effective way to prohibit unsafe language
features. Go also offered safety but with concerns about runtime
costs. Rust looked promising but few people had deep experience with
it. In 2018 I was not able to argue confidently for moving away from C
in QEMU.

Now in 2020 the situation is clearer. C programming bugs are still the
main cause of CVEs in QEMU. Rust has matured, its ecosystem is growing
and healthy, and there are virtualization projects like Crosvm,
Firecracker, and cloud-hypervisor that prove Rust is an effective
language for writing Virtual Machine Monitors (VMM). In the QEMU
community Paolo Bonzini and Sergio Lopez's work on rust-vmm and
vhost-user code inspired me to look more closely at moving away from
C.

Do we need to change programming language?
---------------------------------------------------------------
Most security bugs in QEMU are C programming bugs. This is easy to
verify by looking through the CVE listings. Although I have only
reviewed CVEs it seems likely that non-security bugs are also mostly C
programming bugs.

Eliminating C programming bugs does not necessarily require switching
programming languages. Other approaches to reducing bug rates in
software include:

Coding style rules that forbid unsafe language features.
Building safe abstractions and prohibiting unsafe language features or
library APIs.
Static checkers that scan source code for bugs.
Dynamic sanitizers that run software with instrumentation to identify bugs.
Unit testing and fuzzing.

The problem is, the QEMU community has been doing these things for
years but new bugs are still introduced despite these efforts. It is
certainly possible to spend more energy on these efforts but the
evidence shows that bugs continue to slip through.

There are two issues with these approaches to reducing bugs. First,
although these approaches help find existing bugs, eliminating classes
of bugs so they cannot exist in the first place is a stronger
approach. This is hard to do with C since the language is unsafe,
placing the burden of safety on the programmer.

Second, much of the ability to write safe C code comes with
experience. Custom conventions, APIs, tooling, and processes to reduce
bugs is a hurdle for one-time contributors or newcomers. It makes the
codebase inaccessible unless we accept lower standards for some
contributors. Code quality should depend as little on experience as
possible but C is notorious for being a programming language that
requires a lot of practice before you can write production-quality
code.

Why Rust?
--------------
Safe languages eliminate memory safety bugs (and other classes like
concurrency bugs). Rust made this a priority in its design:

Use-after-free, double-free, memory leaks, and other lifetime bugs are
prevented at compile-time by the borrow checker where the compiler
checks ownership of data.
Buffer overflows and other memory corruptions are prevented by
compile-time and runtime bounds-checking.
Pointer deference bugs are prevented by the absense of NULL pointers
and strict ownership rules.
Uninitialized memory is prevented because all variables and fields
must be initialized.

Rust programs can still "panic" at runtime when safety cannot be
proven at compile time but this does not result in undefined behavior
as seen in C programs. The program simply aborts with a backtrace.
Bugs that could have resulted in arbitrary code execution in C become
at most denial-of-service bugs in Rust. This reduces the severity of
bugs.

As a result of this language design most C programming bugs that
plague QEMU today are either caught by the compiler or turn into a
safe program termination. It is reasonable to expect CVEs to reduce in
number and in severity when switching to Rust.

At the same time Rust eliminates the need for many of the measures
that the QEMU community added onto C because the Rust programming
language and its compiler already enforce safety. This means newcomers
and one-time contributors will not need QEMU-specific experience, can
write production-quality code more easily, and can get their code
merged more quickly. It also means reviewers will have to spend less
time pointing out C programming bugs or asking for changes that comply
with QEMU's way of doing things.

That said, Rust has a reputation for being a scary language due to the
borrow checker. Most programmers have not thought about object
lifetimes and ownership as systematically and explicitly as required
by Rust. This raises the bar to learning the language, but I look at
it this way: learning Rust is humanly possible, writing bug-free C
code is not.

How can we change programming language?
------------------------------------------------------------
When I checked in 2018 QEMU was 1.5 million lines of code. It has
grown since then. Moving a large codebase to a new programming
language is extremely difficult. If people want to convert QEMU to
Rust that would be great, but I personally don't have the appetite to
do it because I think the integration will be messy, result in a lot
of duplication, and there is too much un(der)maintained code that is
hard to convert.

The reason I am writing this post is because device emulation, the
main security attack surface for VMMs, can be done in a separate
program. That program can be written in any language and this is where
Rust comes in. For vhost devices it is possible to write Rust device
backends today and I hope this will become the default approach to
writing new devices.

For non-vhost devices the vfio-user project is working on an interface
out-of-process device emulation. It will be possible to implement
devices in Rust there too.

If you are implementing new device emulation code please consider
doing it in Rust!

Conclusion
---------------
Most security bugs in QEMU today are C programming bugs. Switching to
a safer programming language will significantly reduce security bugs
in QEMU. Rust is now mature and proven enough to use as the language
for device emulation code. Thanks to vhost-user and vfio-user using
Rust for device emulation does not require a big conversion of QEMU
code, it can simply be done in a separate program. This way attack
surfaces can be written in Rust to make them less susceptible to
security bugs going forward.


^ permalink raw reply	[flat|nested] 14+ messages in thread
* Re: Why QEMU should move from C to Rust (clickbait alert ;))
@ 2020-08-21 20:18 Alex Carter
  2020-08-27  8:08 ` Sergio Lopez
  0 siblings, 1 reply; 14+ messages in thread
From: Alex Carter @ 2020-08-21 20:18 UTC (permalink / raw)
  To: stefanha
  Cc: Peter Maydell, Sergio Lopez, Markus Armbruster, qemu-devel,
	Alexander, Paolo Bonzini, Alex Bennée, Dave Gilbert

[-- Attachment #1: Type: text/plain, Size: 3320 bytes --]

Hi everyone,

My name is Alex, I’m a student at the University of Michigan and I just
completed an internship at IBM Research. There, I have been working on a
project very related to this topic. I tested using Cloud Hypervisor’s
Rust-based vhost-user virtiofs and block devices with QEMU. Bigger picture,
I wanted to explore the implications of using Rust for vhost-user devices
in QEMU.



I agree with the points from the original post, namely:

·      C programming bugs are responsible for a large number of CVEs, and
specifically CVEs coming from the implementations of virtual devices.

·      As a programming language, Rust has matured to a point where it is
worth considering it more seriously for production use. It has extensive
libraries and community support. Many big players in the industry are
already using Rust for production workloads.



Full Transparency: the Drawbacks:

It would be deceptive to only showcase Rust in an ideal light.

·      The benchmarks I ran show a noticeable performance hit from
switching to a RustVMM implementation of a virtiofsd device.

·      While Rust has matured greatly, it still is missing a bit. One
example of this that came up was that the rust compiler does not have
Control Flow Integrity (CFI) features. While these are not as important as
in “unsafe” languages such as C, the ability to express unsafe portions of
code does allow for some types of memory bugs – although to a much lesser
extent (an interesting case of this surfaced from Firecracker, and the
handling of mmio [1]). So further protections such as Control Flow
Integrity can still be desirable, even with rust code.

·      There have been years of optimization work put into the C
implementations of these devices, and it’s hard to evaluate how optimized
the relatively novel rust implementations are.

A piece of exciting news is that many of these drawbacks show a pathway for
future improvement. Improvements to rust infrastructure are very realistic.
Rust boils down to LLVM just like C, so porting over C’s CFI features
should be feasible. If more development resources are put into the RustVMM
project, there is no reason their implementations can’t be as optimized as
the C versions, and this could be greatly aided by expertise coming from
the QEMU communities familiarity with these topics.



I believe vhost-user devices are an excellent place to start since It
lowers the entry barrier for developing in Rust. The device only has to
interface with the C-based QEMU binary through a standardized protocol. It
removes many worries of moving entirely away from C, since adding a set of
Rust devices would simply be giving more options and room to explore.



I am putting together the scripts I used for all of the tests at this repo:

https://github.com/Alex-Carter01/Qemu-Rust-Testing

I am working to standardize everything to make it easier to replicate. I
would love any community involvement if people wanted to see how results
differ based on the hardware setup, build configuration of the devices etc.

The repo also has links to a recording of my original presentation and the
slides I was using if you would like to look at that format or see the
discussion which came out of it.

[-- Attachment #2: Type: text/html, Size: 6788 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2020-08-27  8:09 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-08-06 10:24 Why QEMU should move from C to Rust (clickbait alert ;)) Stefan Hajnoczi
2020-08-06 11:08 ` Daniel P. Berrangé
2020-08-06 13:39   ` Alex Bennée
2020-08-07  9:28     ` Stefan Hajnoczi
2020-08-07  9:44   ` Stefan Hajnoczi
2020-08-06 11:51 ` Sergio Lopez
2020-08-06 12:01   ` Daniel P. Berrangé
2020-08-06 13:38     ` Sergio Lopez
2020-08-06 13:43       ` Daniel P. Berrangé
2020-08-07  9:27       ` Stefan Hajnoczi
2020-08-07  9:45         ` Stefan Hajnoczi
2020-08-07  9:39   ` Stefan Hajnoczi
  -- strict thread matches above, loose matches on Subject: below --
2020-08-21 20:18 Alex Carter
2020-08-27  8:08 ` Sergio Lopez

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).