QEMU should move from C to Rust
blog.vmsplice.net
blog.vmsplice.net
Migrations of this size aren't not done because they're technically bad ideas, but exactly because they're expensive, messy, and few people have the appetite or funding to do it. Proposing a solution to that is more interesting that just saying "switch to Rust!".
Also, I don't know much Rust (still on my PL bucket list), but usually when I dive into a more detailed analysis of such a migration the most relevant parts are around how much unsafe code will be required and whether or not integrating with the existing codebase has to be fine-grained or can be done in larger modules like Rust recommends.
I would naively guess that a VM would have lots of unsafe code. Are there any investigations on whether the recent vulnerabilities would have migrated to safe or unsafe code?
edit: mea culpa. I didn't read the second to last-paragraph closely enough, which at least proposes a modularized way of doing this with device emulation being written in Rust in separate modules.
Is it worth the effort to write a "X should switch to Rust" post that ends with "but I personally don't have the appetite to do it"?
he made it to the front page of HN, so I guess the answer is "Yes"I see several comments on the article saying it looks like it might have been written by GPT-3, but there's no confirmation.
There's also a comment on the article itself that is certainly suggestive but doesn't seem to come out and openly state that this was written by GPT-3.
Finally I clicked on the author's name and see a list of several articles but no disclaimer that this author is a bot.
It took some digging to find this
Once again and eventually the response is still PoC||GTFO.
[1] https://lists.nongnu.org/archive/html/qemu-devel/2020-08/msg...
As background, vfio-user was at least partially born of some discussions and a proof of concept last summer for using SPDK to provide virtual NVMe devices into QEMU. These are intended to be high performance devices.
Except SPDK is written in C. So maybe the title should be rewrite SPDK in Rust!
> My KVM Forum 2018 presentation titled Security in QEMU: How Virtual Machines provide Isolation (pdf) (video) 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.
__found the most common causes were C programming bugs. This includes buffer overflows, use-after-free, uninitialized memory, and more__
My usage of rust for now has indicated to me that for most low level tasks you are better of using C or C++. It is more suited to it. There appears to be a lot of boilerplate in rust.
Yeah, the author explicitly acknowledges that:
> 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.
It's safer, in theory, to just do it in Rust first, but it is also important to consider the amount of time it actually takes to implement either.
Why is this garnering downvotes...?
The number of new bugs introduced in a migration would be enormous. It's not just "translating" the C into Rust-- you ideally need to write "idiomatic" Rust.
Rust is a fantastic language but what I despise about its community is how they seem to think every C/C++ codebase should be rewritten in Rust. Either it's a monumental effort or it would decrease the developer base in many cases. In the case of C++ template libraries then it's in some cases even impossible to replicate functionality.
Rust has procedural macros that can replicate anything C++ templates can do, often more cleanly. And C/C++ are hardly immune from logical bugs.
This is an entirely false statement. Wishful thinking makes a poor substitute for knowledge. Promoting wishful thinking against facts does all readers a disservice.
That said,
> Half of those are classes of bugs that would probably still exist with the usage of Rust, that is, they're simply a diversion from what you expected and what actually happens that the borrow checker can't save you from.
It's unclear what you're referring to. The linked article is talking about vulnerabilities in QEMU drivers, which are almost exclusively memory safety issues from my own experience and memory. The post you're replying to is just about tools and techniques for avoiding them.
> but it is also important to consider the amount of time it actually takes to implement either.
No one has said otherwise and the article even explicitly addresses this.
So I find your point really unclear.
What do you mean by this? The article might reference it (I don't see any reference to this), but if it does it doesn't actually explore what factors would influence costs and their magnitude.
That's what I'm looking for.
The article explicitly addresses that it's not so simple to just rewrite a codebase:
> 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.
While personally being a proponent of Rust, I’ve been wondering if some of the projects that have codebases too big to realistically RIIR any time soon might benefit from running statical analysis as a git hook server side rejecting any commits that don’t pass some set of rules.
Though, only having second-hand knowledge of statical analysis of C code through reading blog posts on the net, I am also of the impression that false positives are a common occurrence in statical analysis tools. So based on that I am thinking that it might either not be feasible, or at the very least it would be a major undertaking and you might need to continuously tune the rules and also bugs of this sort would perhaps still slip through.
Could it be that he agrees in principle that Rust is the way to go but for some reasons (time, interest, etc) he does not want to do it.
The firefox way would be more interesting, start by introducing Rust to the codebase, than write first components in it and switch it over time.
From the next to last section "How can we change programming language?":
> 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 all those criticizing the knee-jerk impulse to rewrite, you're arguing against the wrong post!
if this is not the reflective of the content or it is a tongue in check exaggeration following a c common template (similarly to the "considered harmful" titles) it is reasonable to criticize the title
(it is less reasonable to criticize the article under the assumed content)
Not saying Rust is flavour of the week but this happens with a new language every couple of years. Everything doesn't need to be rewritten. You switch languages, you might fix some existing bugs but you open lots of other ones.
There's a lot of this software. And until recently C and C++ were more or less the only viable options for writing it. Now there's Rust, and it has the potential to bring rates of security issues down to the levels of other memory safe languages (or even lower - Rust actually has protections against things like thread-safety issues that languages like Java don't).
If the language didn't matter, then we'd all be writing in assembly code. It can make a big difference.
But then there is a LOT more C/C++ software as well, so it makes sense that when you have a lot more code you'll also have a lot more bugs.
> than (similarly well written) software in other languages.
Why isn't that similarly well written software being used instead of the C/C++ software when the latter ends up with more bugs?
> And until recently C and C++ were more or less the only viable options for writing it.
I do not think that this is the case, there have been alternatives for pretty much as long as C existed. For example Object Pascal existed for decades before Rust and while it doesn't have as many compile-time guarantees as Rust does, it still is safer than C and C++, provides a similar amount of functionality while not losing in terms of low level functionality. Yet outside of a few exceptions (mainly during Borland's heyday) people still went with C or C++ despite those languages not providing anything special compared to it.
And there have been other languages too - i've seen Ada being brought up often as a much safer language (safer than Pascal too) with a strong type system, yet still being usable even on tiny devices.
What makes people stick with C and C++ when other solutions existed for years and how would Rust change that when other languages apparently failed?
70% of C/C++ security bugs are memory management bugs. Those don't (for the most part) exist in GC'd or other non-manually managed memory languages.
> Why isn't that similarly well written software being used instead of the C/C++ software when the latter ends up with more bugs?
Performance and low level control. Familiarity. etc.
I think that's very debatable. Certainly there are classes of bugs with C code that don't exist in other environments. And addressing that is worthwhile.
But "security issues" is a VERY big bucket, and most of them (and frankly most of the most dangerous) aren't about memory protection or heap management at all. Java doesn't prevent you from exposing a database with a default password. Node apps can have XSS vulnerabilities. Access to a Rust app can always be phished.
I know those all seem like specious examples, but the point is that you're using a very narrow definition of "security" (to mean The Stuff Rust Addresses) in one sense, while using a very different definition (Stuff That Is Really Important For Software To Do) in the premise to your argument.
The space between "well-written C++ code" and "well-written Rust code" is a very different number in those two spaces.
And in the one that actually matters... I just don't think it's nearly as big as people like to imagine.
Rust has the ability to compete with them. Other languages don't. So it's ripe for distrupting projects that are normally written in c.
Yet C and C++ still persisted. What makes Rust different this time?
Rust has more advantages than Pascal. A single implementation. A decent package manager, lifetimes, sum types, all the infrastructure around sum types etc
And C and C++ (especially C++) were not standardized for a long time and even after they were, most programs relied a lot on compiler-specific behavior.
Pascal does have sum types (called variant records) and AFAIK had those since the beginning. Not sure about how exactly Ada does its memory management, but AFAIK it isn't a free-for-all like in C or C++, most dynamic objects are stored in containers which handle memory and any custom memory management must be done in explicitly designated ways (which it doesn't sound very different than Rust's unsafe code).
So while Rust does add some stuff, i do not think that they are that much of an improvement over other existing languages (remember that many thought C was a step backwards compared to what other languages provided even at the time). Rust may add a lot compared to C, but very little when compared to other languages.
Also note that i brought up Pascal and Ada as examples here, but those aren't the only alternatives to C and C++ that existed, just a couple that came to my mind. Of course there have been other languages.
Which is really what i refer to above - compared to C or even C++, Rust does add some things but other languages that existed for years (decades in some cases) added to C and C++ and compared to those Rust doesn't add that much (which isn't the same as adding nothing). Yet these languages weren't really adopted and people remained with C/C++.
Do you really think that what Rust provides will succeed in making people adopt it when other languages failed (and let's be honest - while Rust adds some stuff it isn't like it has all the features other languages have either)? Is it even a matter of features (be it about memory safety or anything else) in the first place?
Given the ever broadening adoption of Rust, I'd say it'll definitely have a large foothold. I don't know that anything, no matter how good it is, will every fully replace C or C++. But I think a lot of projects that don't need a specialty compiler (embedded or stuff like game consoles) will start picking up Rust instead of C or C++.
Which makes me wonder how much programmers who use C really care about those features in the first place.
The only functionality standard Pascal offers is the simplest "case" statement where you can match against the variances with only little more functionality than C's select statement (you can have multiple values per case and you can use ranges), but nothing more than that.
In modern Object Pascal it might be possible to implement the functionality using generics and anonymous functions (currently only available in Delphi but soon also in Free Pascal), but AFAIK there isn't any functional programming-like functionality out of the box. In general Pascal is largely an imperative programming language and even in the more advanced dialects there is almost no functional programming functionality.
I consider this one my biggest concerns about adding a Rust dependency to a core package. Especially when in https://forge.rust-lang.org/release/platform-support.html "Tier 1" is so small.
Pascal, by contrast, simply didn't offer any compelling advantages.
(Not that I'm personally a big fan of all these call to rewrite in Rust posts, there's a reason the Rust subreddit discourages ”X should be rewritten in Rust” posts)
There isn't really a trend, those who can are doing it in C++, those who can't are teaching us about the wonders of rewriting in a more fashionable language.
It has all of the safety characteristics of a VM language but its low level with no runtime. Its a direct replacement for C with all the performance and modern design of languages like Java and Go. And it uses LLVM so FFI with other languages that compile to native is simple and zero overhead. You can even do whole program optimization (LTO) on the combined binary, that's huge. Trust me the hype about Rust is real.
Much more real than the hype around Go, which to me just feels like yet another GC language. The hyped AOT compilation is nothing profound. Since the GC forces Go to have a runtime anyways IMO they should have gone all the way and just used JIT. And Go doesn't use existing C compilers so FFI has overhead, can't be optimized together at a bytecode level
For anyone else who was unfamiliar: https://en.wikipedia.org/wiki/ATS_(programming_language)
I wouldn't even call Rust "hipster" anymore. It's already been embraced and rolled out to production by big companies working on hard techinical problems (Cloudflare, AWS, Discord), as well as the crypto community.
I think the reasons from steering away from hipster languages for these critical projects are roughly the same ones we use to justify not using hipster crypto for critical, real-world applications
Twitter isn't an especially hard problem either.
We're eager to know!
AWS is orders of magnitude more complicated than Discord. Frankly, so is World of Warcraft.
What does Discord do that wasn't solved in 2005?
AWS maybe, insomuch as "orders of magnitude" can mean as little as "100x". But still, unconvinced. There's something like 200 AWS services, and Discord on the whole is certainly more than twice as complex as the average AWS service.
World of Warcraft being >100x more complex than Discord doesn't track.
> What does Discord do that wasn't solved in 2005?
Perhaps you are unaware that Discord has (pretty high quality!) voicechat and livestreaming? Certainly much better than anything that existed in 2005.
Discord was pretty much unrivaled in voice-chat quality for a long time, and to this day it's only "real" competitors in technical prowess in this space that come to mind are Apple's Facetime and Google's Duo.
Both Facetime and Duo have bespoke algorithms for this kind of thing: Duo for example leverages SOTA ML to correct audio gaps in the call[0], while Facetime leverages ECN on their custom adaptive bitrate algorithm so that the call is more resilient to noisy networks (couldn't find a good reference for this second one).
Keep in mind that both Google and Apple have highly-qualified teams working exclusively on networking protocols, and yet still there was a time a while ago where Discord pretty much had the best call quality experience around (GMeet is still wonky to this day).
The only thing about this that was "solved" in 2005 is shoveling packets over UDP, or at most, if you wanted to be really fancy, just shoveling them over SCTP instead.
I think you're severely underestimating how much knowledge of networks it takes to build something to par that level of quality. The only thing you can point at back in 2005 is Skype, and they do not come even close. You also seem to be equating difficulty with complexity, which even though they are at times correlated, is still a false equivalency.
[0] https://ai.googleblog.com/2020/04/improving-audio-quality-in...
Also, from what I can tell of its mailing list, ATS is a pretty dead project: https://sourceforge.net/p/ats-lang/mailman/ats-lang-users/ shows only announcements post-2015.
if it were a new project I'd agree, but if there's an existing C codebase, it already contains all these UBs and the goal of the rewrite is to grow a formally-verified critical core functionality in ATS that would still inline the rest of the project intact. This way the formally verified part of the project can grow naturally through small iterative steps without major disruptive changes to the tooling and supportive infrastructure.
People who are familiar with C can acquire basic ATS patterns pretty quickly (within a month or so), and the same is applicable to those who are familiar with ML-family languages.
I think it's worth pointing out that you can't always get away from those undefined behavior situations even if you skip C all together. Rust, for instance, has some internal/implementation details I've run across that are just C undefined behavior details leaking out of the LLVM IR instructions they use to implement the language, since those instructions have the same undefined behavior semantics as the corresponding C code they're used for.
https://github.com/githwxi/ATS-Postiats/blob/master/CHANGES-...
A compiler has greater ability to enforce invariants that make the resulting code safe. The issues with C result from faulty humans; running through a program gives an opportunity for those issues never to occur to begin with.
Makers of compatible chips are obliged to keep a collection of systems with all the extant chip designs to run experiments against, and to maintain their own documentation of discovered but unspecified commonalities that users' code may have come to depend on.
Each released chip, and each stepping of each release, has its own unique set of bugs-- deviations from documentation, from observed behavior of previous chips, and of chips yet to be released.
Writers of assembly code need a compendium of behaviors, documented or not, that cannot be relied on for the set of release platforms. Many such bugs depend on an ill-characterized history of processor states, making them, often, (more or less) reliably reproducible only with a particular program that was discovered to evoke each. Often the behavior noted is seen only once in a million runs.
An example on Intel is the popcount instruction that runs very slowly, sometimes, in chips released up to a few years ago. The instruction appeared along with ...SSE3?, and had the bug until it was noticed and fixed in a subsequent chip. The bug is the reason Gcc uses the same register for source and destination when it emits this instruction. Intel's ISA manual does not mention this behavior.
ATS avoids some things; you shouldn't be able to do the silly memory-unsafe parts.
Stuff like dividing by zero is permissible by default but can be avoided.
Admittedly, if you're switching from C, you start with a pretty poor story about all that. But at least that story is widely and thoroughly understood.
ATS has an optional garbage collector. It seems the standard library has two implementations of each container type, one which uses GC, and one which uses linear types, so does not need GC, but is more demanding to use. That is pretty cool! What is the situation with other libraries? Is there a convention of assuming GC can be used, or that it can't, or of supporting both?
as ATS is a frontend to GCC, it means that the standard library can be any battle-tested C standard library. On top of that there can be a formally-verified interface that calls underlying C API. Here's an example - https://bluishcoder.co.nz/2012/08/30/safer-handling-of-c-mem...
There's also a safe Prelude and common data structures, implemented in ATS:
http://www.ats-lang.org/Libraries.html
> Is there a convention of assuming GC can be used, or that it can't, or of supporting both?
afaik there's no officially defined convention, but you can have a look how this switch may look like in practice in this video - https://youtu.be/Xkg_EmERYRE?t=1742
Personally I think this playlist provides a nice set of real-world examples implemented in ATS:
https://www.youtube.com/watch?v=dsILVOqYCU0&list=PL6BIXG1a4e...
And this series of blogposts is a pure gold:
https://bluishcoder.co.nz/tags/ats/
And here's the official language introductory resources:
Language Tutorial - http://ats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/HTML/...
Language Features Overview - http://ats-lang.sourceforge.net/DOCUMENT/ATS2TUTORIAL/HTML/A...
Two people from the Rust team have posted about their situation, one was laid off and one was not. Unsure about the others. Many of the Servo folks (and possibly all, it's not 100% clear yet but it doesn't look good) have been laid off.
The vast majority of contributors and team members are non-Mozilla, though the Mozilla folk are very important. Rust will survive. This situation is very painful, and it has the possibility of being more so, but (thanks to a lot of work from people (not speaking of myself here) who used to be at Mozilla!) Rust is bigger than Mozilla, and has been on a long road towards diversification. Some other companies have stepped up to pay a bunch of the bills that Mozilla used to pay, namely Amazon and Microsoft. Here's hoping that we get even more involvement in the future.
If widely-used doesn't imply open source then there's a lot of options. Dropbox use Rust in their sync client, as well as in their storage backend. Cloudflare are using it for their VPN. Microsoft are rewriting parts of windows in it. Amazon are using it for their Firecracker micro-vms that power lambda.
Anyway, two big projects in a similar space to QEMU are Firecracker (the underlying virtualization tech for AWS Lambda + Fargate), and Crostini (the underlying virtualization tech for ChromeOS). Firecracker started life as a fork of Crostini and now there's a rich ecosystem going on in this space.
Don't forget the Rust code from Servo that lives in Firefox, too.
Yeah, it's tough to get the combo of all of those things, for other reasons too. I would probably want to first reach for VS: Code, which uses ripgrep for search. But that's a "important component written in Rust", rather than a whole-Rust project. There's tons of tools like ripgrep, which is the most well-known, but it's hard to say how popular they are. And there are things like 1password, which do run on people's machines, but aren't open source.
I actually have recently seen a bug report that implies something really, really huge in this space, but I don't want to jinx it, so I'm not gonna link just yet. We'll see :)
https://aws.amazon.com/blogs/opensource/aws-sponsorship-of-t...
> having a minor part written in Rust
"every single CSS bit touches this code" isn't a minor part, and it's not the only part. https://4e6.github.io/firefox-lang-stats/ is a sorta flawed metric but it reports nearly 10% being Rust.
It’s not so much about finance as it is holding the trademark, imho.
-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.
These are all only true in safe rust. A hypervisor has to do low level things like translate memory addresses, move stack pointers around, etc. Nearly all the buggy C code, if implemented in Rust, would be wrapped in 'unsafe' and would be just as buggy.
I recommend everyone interested in Rust to take a look at how the standard library Vec is implemented[1]. The code is littered with `unsafe` - There is just no way to avoid it and do something useful at the same time.
This isn't really a shortcoming of the language, but of modern computers. It is fundamentally an unsafe operation to read or write memory, to communicate with a disk, etc. Every computer program is fundamentally unsafe. Rust does a fantastic job of making this explicit and controlling it as much as possible, but the idea that Rust code is bug free for free is just wrong.
> There is just no way to avoid it and do something useful at the same time.
I don't think that's true. Your code might have to rely on code down the abstraction layers that uses unsafe, as interacting with the hardware is inhere you unsafe, but that doesn't mean that any code you want to write won't be able to leverage the safe abstractions. The argument you're making sounds to me, and please correct me if I'm misunderstanding, that trying to create safe abstractions is sheer folly so we might as well not do so.
I've been writing Rust code for years now and I've never had to write unsafe code myself other than when interacting with C code and when doing so I've found issues with the way the API the C libraries were exposing having fundamental issues.
This is the point I was trying to make by linking to the vec code. Any useful Rust program will run unsafe code. That code might just be hidden in a library. Ultimately, you are trusting that the code author did not write any bugs - in this regard you are not much safer than using the C++ stl.
> The argument you're making sounds to me, and please correct me if I'm misunderstanding, that trying to create safe abstractions is sheer folly so we might as well not do so.
On the contrary! I think what Rust is doing is a big step forward. But it is very important to keep in mind the limitations of a system.
The authors attitude of "This is written in Rust, so it must be free of memory bugs!" is dangerous. The key benefit of Rust is to isolate and explicate the dangerous parts of your program (because there are dangerous parts!!). This should make you more vigilant of bugs, but the "Eh, the borrow checker will debug for me" attitude can often lead to programmers being less critical of their own code.
Of course, none of this really applies if you are doing higher level stuff. But QEMU would definitely have to write their own 'unsafe' code.
> I recommend everyone interested in Rust to take a look at how the standard library Vec is implemented[1]. The code is littered with `unsafe` - There is just no way to avoid it and do something useful at the same time.
I think Vec is a somewhat extreme example in terms of unsafe. It requires to be able to realloc, or allocate a new buffer and move all elements; those operations do not fit into Rusts safe memory and lifetime model. If you are writing some form of container like Vec or Hashmap, I would agree with you; Rust doesn't offer much help in preventing those memory bugs.
However, there is tons of other code than can be written in safe rust. Parsing binary data formats in particular is an area that can result in buggy C code and can be solved in Safe Rust. If you were referring only to the buggy code in qemu, that may very well be true. However, I would suspect there large swaths of code that don't do anything particularly interesting, but do allocate and free which Safe Rust might help with.
> This isn't really a shortcoming of the language, but of modern computers. It is fundamentally an unsafe operation to read or write memory, to communicate with a disk, etc. Every computer program is fundamentally unsafe. Rust does a fantastic job of making this explicit and controlling it as much as possible, but the idea that Rust code is bug free for free is just wrong.
If you trust the standard library to abide by Rust's memory invariants, you totally do unsafe operations without letting program state go into an undefined state. I don't think I have ever had a Rust program using only safe rust (in the main source code) segfault and that is simply no where close to true for C programs I have worked on and other tools I have used.
The feature that I like best about the safe vs unsafe Rust is that if I only use well established libraries and only write safe rust, I can almost completely ensure my code won't segfault (even if I am incompetent). Panics are still a problem, but they are more manageable.
What architectures can rustc target? Can it cross-compile? Can I cross-compile rustc itself, or do a Canadian-cross (where I cross-compile a rustc that wants to target a different architecture than the one that hosts the compiler)?
Speaking as somebody who does a ton of system programming for embedded Linux systems, this is basically C/C++'s biggest advantage over Rust - the extreme flexibility of the available toolchains.
ARM themselves are committing to getting the various ARM targets to Tier 1 support. AVR support landed in nightly recently. Other targets have less support, but that's mostly due to lack of people power, not a lack of interest from us.
So the availability of a C cross-compiler toolchain can affect your ability to compile Rust code for foreign architectures. As a concrete example, at $dayjob we need to compile our code for CentOS 7 armv7 and aarch64, but CentOS 7 does not have a usable cross-compiler toolchain in its repos [2], so we have to run the build process in a centos7 arm container running under qemu.
[1]: Eg openssl-sys is bindings to openssl and expects you to have installed the equivalent of your distro's openssl-devel package. In cross-compilation scenarios, this means installing the openssl-devel package for the foreign arch. For debian you'd do something like `dpkg --add-architecture armhf; apt install libssl-dev:armhf`
[2]: What it has is only for cross-compiling the kernel, so there's no cross glibc available to link the final binary to.
I attended a hack session where the attendees had zero Rust experience and they were able to get blinken led running in under an hour. Basically 10 fullstack web developers were able to open the package on the devkit, install rustup on windows/mac/linux and start writing firmware and updating the board.
Pretty solid I'd say.
What a 1.5M LoC Rust low level kind of project looks like?
That very low level educational project can show how little unsafe is needed even at things running on bare metal.
I think you overestimate how much unsafe would be required. Most code, even low-level code can be safe.
Rust code does have unsafe at times, so it can still have memory safety issues.
It may not matter that your program is memory safe if it was written by people who don't understand the problem domain and doesn't work correctly. E.g. for qemu, it's perfectly possible to be absurdly vulnerable -- giving target code control of the host -- without any memory safety bug at all.
> without any memory safety bug at all.
Most QEMU escapes I have seen are memory safety issues in emulated devices.
Hi, Article author here. I am not assuming Rust will fix all security issues. Bugs are still possible even in safe code, plus there will be unsafe code as you mentioned.
Unsafe code also worried me when evaluating Rust. Given the nature of Virtual Machine Monitors and emulators, isn't a lot of the program going to be unsafe? After studying existing Rust codebases and writing programs myself I found that it's still a significant improvement over C.
Whether Rust is safe enough depends on your requirements. For the QEMU, I think the answer is yes. For writing the firmware for a pacemaker implant or control software for a nuclear powerplant, I don't know :).
Probably, RUST Devs who are well versed in emulation can start another project in RUST which has same goals of QEMU but telling existing software to rewrite is a big JOKE to be laughed at.
This has nothing to do with RUST but "Rewrite in New language" syndrome.
Secondly, you may be started to find out that the QEMU developers seem to be in agreement, with the interest related to Rust for vhost-user, and considering ways interfaces etc. might make that feasible.
OPs post to the QEMU development list, thread makes for interesting reading: https://lore.kernel.org/qemu-devel/CAJSP0QWF8g7r5VqU_PRbskWZ...
I'm not a QEMU developer. I used to be pretty active in Apache HTTPD, APR and related projects. They are large user space code bases written in C - with, overall, a relatively OK security record.
I think Apache should be on a path to be rewritten in Rust. Here's why...
Every new line of C has a chance of a remotely exploitable vulnerability. No matter the precautions taken, no matter the developer who writes it. HTTPD has a long history, precautions like memory pools from APR and uses "safe" string functions, but it still has issues.
Apache's core C code doesn't change much, so yes, many remotely exploitable memory corruption bugs have been fixed over 20+ years, but new code, new code still has bugs. And they can be bad.
Look at the recent known vulnerabilities in httpd: https://httpd.apache.org/security/vulnerabilities_24.html
Vulns that are largely fixed by Rust are concentrated areas like HTTP/2 support and the Proxy - areas under active development. Vulns around logical errors are still there, and more widespread, but largely have a lower impact.
So, I emphasize with QEMU developers. I'm in the same boat. I have a full time job, and that job is not to work on Apache HTTPD. It would take a full time job to incrementally adopt Rust. The outcome would be in 24+ months, no more remote memory corruption bugs. Is it worth it to fund this? Can you put a price tag on this for the dozens of "core infrastructure" software projects written in C?
I cannot perform a non-blocking operation (querying redis for example) from within my module's handler function because as soon as my handler returns httpd sends a response. i.e. there's no 'NOT_DONE_YET' return code?
And while I'm anonymously ranting on the internet...
- being able to control response headers completely would be nice. In our case, the Date and Server headers cost money to send and our clients don't care about them. It's not for security reasons, it's about traffic egress costs on the cloud
- having a way to hook a worker thread's init would be useful
- there must be an easier way to get a request body other than the bucket brigade stuff?
2) You can control all response filters at the byte level with an Output Filter.
3) Hooks already exist for this: https://ci.apache.org/projects/httpd/trunk/doxygen/group__ho...
4) No. Bucket Brigades is the API for this. It's an efficient linked-list of future-data. It's a good API IMO, just needs some understanding, and because its in C, its full of macros (there are more alternatives to making it cleaner if we weren't using C)
2) yes, but there's a config directive for the Server header too that could just allow people to turn it off
3) for child_init, but nothing obvious that maps to a worker_thread_init
Are there plans for httpd to avail of io_uring if the kernel provides it?
I will admit, I've struggled with configuring httpd for years. A single threaded redis server can handle more connections than a full httpd install.
It's simply impossible to write completely safe c code. Lots of bug like heart bleed, dirty cow, whatever, you name it was write by people that have dozens years of experiment and they still make accidents.
Switch the language is expensive of course. But it might worth it eventually if this project continue to run for a long time (or the project got abandoned before it pays off, who knows?)
In short the article doesn't address what new costs Rust might bring that are intrinsic to using Rust (as opposed to costs that are inherent in making a change to _any_ new language).
I always wonder about the specifics of how these happen!
Once I read someone saying they where blind and had forgotten the context or navigated back or something without noticing. I think there were some interesting follow up questions as well.
Still slower than we'd like. Some folks are putting in a heroic amount of effort to improve this significantly, but it's going to be a long time before it really happens. Smaller stuff is helping all the time, but has less dramatic impact.
> How many times slower than C does it compile?
Really impossible to say, because it varies along so many different factors. C will almost always compile faster though, it's true.
> Any links to statistics? I know it's hard to compare, but I am interested in developing a gut feeling of what to expect.
The closest we have is a few bits of basically anecdotal evidence; we have projects demonstrating that rustc got about 3x faster since 1.0, and we have had at least one (in my mind) pretty reasonable C++/Rust comparison that showed them as being roughly equal. But it's just really hard to get good data here.
You should expect something roughly C++-like.
I would be very curious to compare speed, size and compilation time of the two versions.
For those who don't know, the original author of QEMU is Fabrice Bellard. This guy has several winning entries in the IOCCC. One of them is a C compiler, that once de-obfuscated, forms the basis of TinyCC.
QEMU C code makes heavy use of macros and gcc extensions. It really pushes C to the limit, it even broke my syntax analysis tools.
Now, if the Rust community wants to write a new emulator in Rust, why not, but starting with QEMU may not be the easiest way.
The author applies the same standard reasons for moving from C to Rust for the QEMU project which are valid reasons. However, I would take the author more seriously if they have done a proof of concept first and then later made their case for this.
Otherwise, it is another "rewrite it in rust" post which is yet to materialise into a real project.
I'm not sure you can reasonably said that "it is another 'rewrite it in rust' post..." if it's coming from a QEMU maintainer.
Besides, before starting a large engineering project like this, it's worthwhile to write a high-level proposal _then_ write code. Saves you a lot of wasted effort!
> - Static checkers that scan source code for bugs.
Does QEMU use a sound static analyzer (like IKOS [1])?
The challenge with static analyzers is that false positives make people not want to deal with the analyzer reports.
I will check out IKOS, thanks!
Nah, too much trouble. I'd rather not check if denom = 0. Back to writing autonomous car code!
There may be some overlap, but just "contributing to Firecracker" ignores the goals of these projects.
People suggesting rewrites in X/Y/Z are usually not people maintaining these projects. This is evangelism, but it doesn't help with anything.
The goal of the article is to start a wider discussion in the QEMU community and encourage others to do the same. I will post more about the things I have been working on when they are ready.