We helped found the Bytecode Alliance in 2019 with a mission to create an open-source community collaborating on WebAssembly-based compiler tools and foundations that work across many platforms. WebAssembly is the foundation of our serverless compute environment, Compute@Edge, and we continue to invest in its future because WebAssembly programs carry stronger security guarantees than native code.
Today we want to tell you about an important security component of our WebAssembly implementation: Cranelift, an open-source, next-generation code generator for use with WebAssembly to provide sandboxed security.
In a recent post, you can read how we detected and responded to a particular security issue in Cranelift before it could be exploited. In this post, we will talk about the ways that we proactively and continuously work to find issues like this one, both in focused, security-specific assessments, and as part of our normal development processes. We strongly believe that for software to be secure, one must consider security throughout the development lifecycle, drawing from a diverse array of tools and techniques.
In this post we’ll focus on two of those techniques: we’ll describe how we apply “fuzzing,” a well-known testing methodology, and we’ll describe how we recently ran a full security assessment on Cranelift’s new code-generation backend. Let’s learn some more about what Cranelift is and how we work to improve it!
What is Cranelift?
Cranelift is a native code generator that takes an architecture-independent description of a program and generates fast code native to the particular processor it’s running on. It serves as a key pillar in the Bytecode Alliance’s work toward building secure, efficient software foundations.
Cranelift was originally intended as a possible addition to Firefox’s compiler backends, but the Cranelift team has since built the engine to be useful in many contexts beyond Firefox. The Bytecode Alliance continues to build a community of users and contributors around Cranelift, including WebAssembly engines built on top of Cranelift, like the Lucet and Wasmtime runtimes. Alongside the Bytecode Alliance, we are actively working to improve its performance and security -- work that benefits all users of this project.
Secure, safe sandboxing for Compute@Edge
So how does it work? Using Cranelift, WebAssembly engines can take an untrusted WebAssembly program and compile it to safe, sandboxed machine code. As Cranelift translates the original WebAssembly code to machine code, it inserts safety and security checks that are performed as the code executes. Thus, it is important to verify that the machine code is a correct translation of the original WebAssembly with inserted sandboxing checks. As we noted in a recent post, there are additional safeguards in place if these checks fail; but we work hard to avoid relying on that!
This approach allows Compute@Edge to execute services efficiently with very fast startup times. This is possible because instead of relying on operating system processes (like modern browsers or some shared hosting platforms), containers (like many serverless cloud offerings), or entire virtual machines (like traditional unmanaged cloud hosting) to separate the different services and requests, we use lightweight inline sandboxing checks in native code. By doing so, native code from several services can safely coexist in a single OS process.
We work hard to ensure that Cranelift compiles code in a way that maintains all of the security sandboxing checks, and yet is fast enough for our customers to put in front of every single web request to their sites.
The testing process: fuzzing and security audits
We’ve established that correct code compilation is very important for the security of the services that our customers rely upon, and any miscompilation is a serious issue. How do we work to ensure that the compiler lives up to this standard?
The first technique we use is called “fuzzing.” This is a form of testing that throws many different random inputs at a program in an attempt to break it. It’s a powerful way to test programs because the random inputs will hit edge cases that testers might not think of when writing manual tests. A good fuzzing framework will actually observe how the program responds to these inputs and find ways to hit every single corner-case in the program, an approach known as “feedback-directed fuzzing.” This systematic approach has an uncanny ability to discover overlooked bugs.
Mozilla had already rigorously fuzzed Cranelift, but we do our own testing as well. Today, the compiler has continuous fuzzing through the Wasmtime project’s participation in Google’s OSS-Fuzz infrastructure fuzzing project. In fact, it was the first project written mainly in Rust to be accepted into the OSS-Fuzz program. As part of our drive to improve Cranelift’s fuzzing-based testing, we added code to compare Cranelift-based execution to a WebAssembly interpreter, compare multiple Cranelift backends to each other, symbolically prove correct register allocation, and more. The Bytecode Alliance has noted that fuzzing is an especially powerful way to find compiler and runtime bugs, and we agree!
We also teamed up with security firm Atredis Partners for a focused security assessment. This evaluation involved both manual static analysis and dynamic testing. It focused on register allocation, instruction encoding and optimizations, and any potential attack surfaces where the runtime interfaces with the generated code. The assessment included a survey of existing fuzzing harnesses in order to ensure good code coverage. This assessment found that the Lucet runtime and the new Cranelift backend were well-designed and implemented and made appropriate use of testing techniques including fuzzing.
Putting it all together
We continue to do thorough testing and verification as we develop the compiler itself and its integrations into larger systems (like Lucet). Add to that the processes we’ve put in place (both human and technical) to respond to bugs when they do occur, and we are confident that Cranelift can serve as a reliable, fast, and secure component of our serverless computing environment. As Cranelift continues to power sandboxing for Compute@Edge, we’ll continue to invest in its speed and quality, for both our customers and the greater open-source community as a whole.