Memory Safety in WebAssembly

An in-depth overview of the importance of memory safety in WebAssembly when running code on the web browser.

Digital Delivery
-
10 min
Digital Delivery
/
Memory Safety in WebAssembly

Memory safety is an integral part of any software project, but it becomes even more critical when running WebAssembly code on the web browser.

In recent years we have seen several high-profile vulnerabilities in popular browsers, including the recent Meltdown and Spectre bugs.

In this matter, Memory Safety guarantees that users cannot access memory locations they cannot read from or write to.

The WebAssembly Memory Safety API provides facilities for enforcing these guarantees.

WebAssembly Overview

WebAssembly is a compilation target for deploying applications written in high-level languages on the web.

Web browser engines confine the execution of compiled Wasm programs in a memory-safe sandbox to protect them from exploits.

However, classic memory safety vulnerabilities can still corrupt the environment outside the sandbox's protections and allow attacks within Wasm code.

WebAssembly memory

WebAssembly memory gets stored as a contiguous, mutable region of uninterpreted bytes. It can grow dynamically to match what's needed.

The bytes can be changed by the WebAssembly module, through instructions on that memory instance, or by interaction with the host. The runtime is exported from the WebAssembly module.

WebAssembly code is processed in sequence rather than on an as-needed basis.

The stack machine model of WebAssembly suggests that there are no references to objects stored more than three words down the stack from the current pointer position because those objects can either be compiled out of line or dereferenced with absolute addresses only.

To mutate the bytes, you can use memory instructions.

Security

The security model of WebAssembly has two important goals.

  1. To protect memory safety by guarding against buggy or malicious modules
  2. Provide developers with security primitives and mitigations for developing safe applications.

While memory safety in WebAssembly is fairly secure, that does not mean there are no potential vulnerabilities.

Memory safety in WebAssembly relies on the security guarantees that isolate the Wasm environment from other execution contexts without relying on a hardware memory barrier to enforce this isolation.

What's the risk?

Attackers cannot perform specific code injection attacks because they depend on the web application's state.

But other types of code re-usage attacks are possible and can lead to arbitrary control hijacking.

In this way, we should highlight memory safety in WebAssembly to prevent problems arising from bugs in various programming languages that programmers traditionally use to create their modules for deployment.

There are three primary risks to the security of WebAssembly.

  • Indirect calls
  • Time of check to time of use
  • Side-channel attacks

The most common type of risk to memory safety in WebAssembly is the potential for side-channel attacks.

Attackers cannot perform specific code injection attacks because they depend on the web application's state and rely on information leaks outside WebAssembly's protection space.

But there are many types of re-usage attacks possible, leading to arbitrary control hijacking when an attacker finds out what address contains sensitive data by observing it through timing or cache snooping side channels.

Side-channel vulnerabilities arise due to insufficient timing information about accesses to guarded objects such as caches or TLBs and may allow malicious actors.

Memory Safety

The Memory Safety API enforces memory safety for WebAssembly programs.

The Memory Safety API provides facilities to protect against reading and write accesses outside of permitted bounds on an array.

Arbitrary memory writes in a specified range with complete control over permissions (e.g., protecting from both reads and writes).

All Memory Safe Functions get compiled to valid Wasm code without introducing any security vulnerabilities of their own.

This means there cannot be any buffer overflow or out-of-bounds error cases because these errors can lead to exploitable behaviors that violate memory safety guarantees.

The Memory Safety API takes advantage of type system features available only when compiling to WebAssembly, such as linear types, which provide transparent compile-time enforcement at runtime.

Along with the Memory Safety API, WebAssemby memory is a JavaScript object that does provide additional security in two main ways, preventing memory leaks and providing memory isolation.

Memory leaks

Memory leaks occur when a module instance gains direct memory access, and it does not clear the memory before going out of scope.

memory leaks in webassembly

Since the memory object is JavaScript, although it gets tracked by the garbage collector, the content itself is not tracked.

The safety in WebAssembly lies in the fact that when the memory object attached goes out of scope, the entire memory array will be garbage collected.

Memory isolation

The Memory Isolation API provides facilities to protect against shared memory writes between two modules with different permissions (e.g., one module can read and change data while another cannot).

This protects against vulnerabilities such as dangling pointers where an attacker might use knowledge of a pointer location from one context to attack it in another.

The Memory Isolation API takes advantage of type system features available only when compiling to WebAssembly, such as linear types, which provide transparent compile-time enforcement at runtime.

It's also worth mentioning that the Memory Isolation APIs are optimized for speed because these operations need to be fast to properly safeguard from attacks.

Control-Flow Integrity

Within WebAssembly, Control-flow integrity (CFI) is enforced by the Memory Safety API. CFI protects against code-reuse attacks, such as Return Oriented Programming (ROP).

The efficacy of control-flow integrity can be measured based on its completion.

Generally, three external control-flow transitions need to be safeguarded because the caller may not be trusted.

Those are direct function calls, indirect function calls, and returns.

To ensure memory safety, WebAssembly will use an expected control flow graph when it is compiled.

Vectors of computer-readable instructions can be made safe by inserting runtime instrumentation at every call site to verify that the transition is safe.

Conclusion

After analyzing the memory safety in WebAssembly, it is apparent that the Memory Safety API will prevent overflows, buffer overflow, and out-of-bounds errors from occurring.

Memory safety is dependent on the security guarantees that isolate WebAssembly execution contexts without relying on a hardware memory barrier.

Memory safety in Web Assembly relies on type system features available only when compiling to Wasm code, such as linear types, which provide transparent runtime enforcement about where data may be read or written.

The current memory safety in WebAssembly is sufficient in the short term.

However, in the long run, additional features will be required to safeguard the WebAssembly platform.

Published on
January 6, 2021

Industry insights you won’t delete. Delivered to your inbox weekly.

Other posts