logo

gVisor - Core Tagging

In gVisor, Core Tagging (also known as Core Scheduling) is a security feature designed to mitigate side-channel attacks (like Spectre, Meltdown, and MDS) that exploit vulnerabilities in CPU Hyper-threading.

The Problem: Hyper-threading Vulnerabilities

Modern CPUs use Simultaneous Multithreading (SMT), or Hyper-threading. This allows two logical CPU cores (threads) to share the same physical hardware resources (execution units, L1/L2 caches).

The security risk is that a malicious process on Thread A can "spy" on the data or cache state of a process on Thread B because they share the same physical core. In a cloud or container environment, this means a compromised container could potentially steal secrets from the host kernel or another container.

The Solution: Core Tagging

Core Tagging allows the Linux kernel to group processes. The kernel's scheduler ensures that only processes with the same "tag" are allowed to run on the same physical core simultaneously.

  • If Sandbox A is running on Thread 0, the kernel will only allow processes from Sandbox A to run on Thread 1.
  • If no other process from Sandbox A is ready to run, Thread 1 is forced to stay idle, even if there are processes from Sandbox B or the Host waiting to run.

How it Works in gVisor (runsc)

gVisor implements this using the Linux prctl(PR_SCHED_CORE) system call. When enabled, runsc creates a unique "Core Scheduling Tag" for each sandbox.

  1. Isolation: Every gVisor sandbox (Sentry) gets its own unique tag.
  2. Mutual Exclusion: This prevents the gVisor sandbox from ever sharing a physical CPU core with:
    • The Host OS.
    • Another gVisor sandbox.
    • A standard runc container.
  3. Kernel Protection: Because the gVisor Sentry handles syscalls and sensitive data in user-space, core tagging ensures that no "sibling" thread can snoop on the Sentry's memory operations.

How to Enable It

Core tagging is not always enabled by default because it requires a relatively modern Linux kernel (v5.14 or later).

To enable it in gVisor, you use the --core-scheduling flag:

Using runsc directly:

runsc --core-scheduling run <container-id>

In Docker (/etc/docker/daemon.json):

{
  "runtimes": {
    "runsc": {
      "path": "/usr/local/bin/runsc",
      "runtimeArgs": ["--core-scheduling"]
    }
  }
}

Performance vs. Security Trade-off

While Core Tagging is a massive security win, it comes with a performance cost:

  • The "Idle" Tax: If a container only has one active process, the "sibling" logical core on that physical CPU becomes unusable for anything else. This can result in a up to 50% drop in total system throughput on highly utilized servers.
  • Context Switching: The kernel scheduler has more work to do to ensure that tags are never mixed on a physical core.

When to use it?

  • Use it if: You are running untrusted/multi-tenant code (e.g., a SaaS platform where users upload their own scripts) and you want to prevent cross-container data leakage.
  • Disable it if: You trust all the code running on your machine and you need maximum CPU performance/density.

Verification: You can check if a process has core scheduling enabled by looking at /proc/<pid>/status and searching for CoreSched. A value of 1 indicates it is enabled.