logo

gVisor - uRPC

In gVisor, uRPC (Micro RPC) is a custom, lightweight, internal Remote Procedure Call protocol used for communication between gVisor's different system components—specifically between the Sentry and the Gofer.

To understand why uRPC exists, you first have to look at how gVisor is structured.

The Context: gVisor's Architecture

gVisor splits a traditional operating system kernel into user-space parts to isolate untrusted applications:

  1. The Sentry: This is the core "guest kernel." It intercepts and emulates system calls for the application. For security reasons, the Sentry is completely isolated and is not allowed to touch the host filesystem directly.
  2. The Gofer: This is a separate, isolated file proxy process. When the Sentry needs to open, read, or write a file on the host machine, it cannot do it itself. It must ask the Gofer to do it on its behalf.

Because the Sentry and the Gofer are separate processes, they need a fast, secure way to talk to each other across process boundaries. That is where uRPC comes in.

What Exactly is uRPC?

Originally, gVisor used a modified version of the 9P transport protocol (an old network file protocol from the Plan 9 operating system) for Sentry-to-Gofer communication. While 9P worked well for standard file operations, it was rigid and difficult to extend when gVisor needed to pass complex control commands or handle operations that didn't fit into standard 9P file abstractions.

To solve this, the gVisor team created uRPC.

  • An Internal RPC: Unlike gRPC (which uses HTTP/2 and Protocol Buffers over networks), uRPC is optimized strictly for Inter-Process Communication (IPC) on the same host machine, typically communicating over Unix domain sockets or shared memory.
  • Simple and Fast: It has very low serialization/deserialization overhead, which is critical because every file operation an application makes translates into a message passed over this protocol.

How uRPC is Used

Within gVisor, uRPC handles two primary types of traffic:

A. Control and Management Commands

When you use tools like runsc (gVisor's runtime CLI) to look at a running container, dump its state, or manage container lifecycles, those control commands are packed into uRPC messages and sent directly to the Sentry.

B. Optimized File Operations (The Newer Gofer Model)

In modern versions of gVisor, the Gofer protocol has shifted toward using uRPC. Instead of translating file operations into generic 9P messages, the Sentry can invoke specific uRPC methods on the Gofer, such as:

  • Open(path)
  • Read(fd, offset, length)
  • GetAttr(fd)

By using uRPC, the gVisor team can easily add new fields, optimizations, or brand-new methods to the file proxy system without breaking a strict, legacy networking protocol spec.

Why not use net/rpc?

It comes down to one single, massively important feature that Go's standard net/rpc does not support: passing raw File Descriptors (FDs) over a socket.

Go's standard net/rpc is built to only serialize and send plain data (like strings, integers, and structs) over network connections using standard JSON or Gob encoding.

However, gVisor has an extremely unique security architecture. The heavily confined Sentry server isn't allowed to open files on the host filesystem. Instead, the runsc client opens the file and passes the actual, physical OS File Descriptor across the Unix Domain Socket to the Sentry.

This is done using a very specific, low-level Linux mechanism called SCM_RIGHTS (ancillary data over Unix sockets).

Source Code

You can review the package code and documentation on the urpc package - gvisor.dev/gvisor/pkg/urpc page.

Summary

In short, uRPC is gVisor's internal telephone wire. It is a lightweight, custom RPC mechanism written in Go that allows the sandboxed guest kernel (Sentry) to securely and rapidly talk to its file proxy (Gofer) and control utilities, ensuring that file access remains highly isolated without completely destroying system performance.