logo

Linux - SCM

What is SCM (Socket Control Message)?

From a high level, SCM (Socket Control Message) is the "Trusted Sidecar" of the Linux networking world.

If you think of a standard data packet as a Letter, then an SCM is the Certified Mail Stamp and the Physical Key taped to the outside of the envelope by the Postmaster (the Kernel).

The Core Concept: Data vs. Metadata

Normally, when two processes talk over a socket, they send Data (strings, bytes, JSON). The kernel doesn't care what's in that data; it just delivers the bits.

SCM is different. It is Ancillary Data (extra data) that the kernel handles specifically. It allows you to send things that are impossible to represent as plain text, or things that require the Kernel's word of honor.

The Three "High-Level" Roles of SCM

A. The "Physical Key" (Capability)

With SCM_RIGHTS, SCM allows you to send a File Descriptor.

  • You can't "text" a file descriptor number to someone. If I tell you "I have FD 5," it means nothing to you.
  • Using SCM, the kernel physically clones the handle into your process.
  • High-level view: It allows processes to "pass the baton" or "share a tool" securely.

Read more below.

B. The "Trusted ID Card" (Identity)

Normally, a process can lie about who it is. A malicious app can send a message saying "I am the Admin."

  • With SCM_CREDENTIALS, the kernel attaches the sender's real Process ID and User ID to the message.
  • The receiver doesn't have to "believe" the message; it looks at the SCM and knows for a fact who sent it because the Kernel put it there.
  • High-level view: It provides a "zero-trust" way to verify identity between containers or services.

C. The "Precision Postmark" (Telemetry)

If an application needs to know exactly when a message arrived (down to the nanosecond), it can't rely on its own clock, because the app might have been "asleep" when the message arrived.

  • Using SCM_TIMESTAMP, the kernel stamps the arrival time the moment the hardware received the bits.
  • High-level view: It provides "hard proof" of timing that is independent of how busy the application is.

The "Certified Mail" Analogy

Imagine you are sending a package to a friend:

  1. The Data: This is what's inside the box (the bits).
  2. The SCM: This is the Postmaster's Stamp on the outside.
    • The Postmaster verifies the ID of the sender (SCM_CREDENTIALS).
    • The Postmaster records the exact time the box hit the counter (SCM_TIMESTAMP).
    • The Postmaster includes a duplicate key to a locker (SCM_RIGHTS).

When your friend receives the box, they don't just look inside. They look at the stamps from the Postmaster to decide if they can trust the package and what permissions they have with it.

Why does SCM only work on Unix Sockets?

Most SCM types only work on Unix Domain Sockets (AF_UNIX) because the sender and receiver must be on the same physical machine.

  • You can't "pass a file handle" (SCM_RIGHTS) to a computer in another building.
  • You can't verify a PID (SCM_CREDENTIALS) of a computer across the ocean.

SCM_RIGHTS

SCM_RIGHTS (Socket Control Message: Rights) is the "magic" Linux mechanism that allows one process to physically share an open file handle with another process.

To understand SCM_RIGHTS, you first have to remember the rule: File Descriptors (FDs) are per-process.

If Process A has a file open at FD 5 and simply sends the number "5" to Process B over a pipe, Process B is in trouble. To Process B, FD 5 might be a network socket, a totally different file, or nothing at all. You can't just "hand over" the integer.

The Core Concept

SCM_RIGHTS is a special type of "Ancillary Data" (also called control messages) sent over a Unix Domain Socket.

When you use it, you aren't just sending a message; you are asking the Linux Kernel to intervene. The kernel takes the file handle from Process A’s private table and clones it into Process B’s private table.

How it works (The Step-by-Step)

Imagine the Gofer has opened a file and wants to give it to the Sentry:

  1. The Open: The Gofer calls open("/etc/config"). The kernel gives the Gofer FD 3.
  2. The Package: The Gofer prepares a message. It puts the integer 3 into a special structure called a cmsg (control message) and labels it SCM_RIGHTS.
  3. The Send: The Gofer sends this over a Unix Domain Socket using the sendmsg() system call.
  4. The Kernel Intervention: As the message passes through the kernel, the kernel sees the SCM_RIGHTS label. It doesn't just pass the bits; it:
    • Looks up what FD 3 is in the Gofer's table.
    • Finds an empty slot in the Sentry's table (let's say FD 8).
    • Makes Sentry's FD 8 point to the exact same file object in the Global Open File Table.
  5. The Receipt: The Sentry calls recvmsg(). It receives the data, and suddenly, its FD table has a new entry (FD 8) that it can use to read the file.

Why is this critical for gVisor?

This is the cornerstone of gVisor's security model.

  • Restriction: The Sentry is running untrusted code, so it is blocked (via Seccomp) from calling open(). If it tries, the host kernel kills it.
  • Delegation: The Sentry can still use files, it just can't originate the access.
  • The Hand-off: By using SCM_RIGHTS, the Gofer (which has permissions) can "open the door" and then hand the "handle" to the Sentry.

This allows the Sentry to perform high-speed read() and write() operations directly on the host's file descriptor without having to talk to the Gofer for every single byte of data.

Technical Summary

  • Type: Ancillary data (control message).
  • Socket Type: Only works on Unix Domain Sockets (AF_UNIX). You cannot do this over TCP/IP or the network.
  • The Result: The receiving process gets a new FD integer, but that integer points to the same underlying "Open File Description" in the kernel.
  • Permissions: The kernel verifies that the sender actually has the right to the file before duplicating it.

Without SCM_RIGHTS, gVisor's performance would be unusable because the Sentry and Gofer would have to copy every single block of data back and forth over a socket. Instead, they just share the "Right" to the file.

More Examples

While SCM_RIGHTS is the most famous because it physically modifies the receiver's environment (adding an FD), the other SCM (Socket Control Message) types are primarily used for Identity and Security.

In the Linux kernel, these are grouped under the category of "Ancillary Data." Here are the other major SCM types:

SCM_CREDENTIALS (The "ID Badge")

This is the second most common SCM type. It allows a process to "prove" who it is to another process.

  • What it sends: A struct ucred containing:
    • PID: The Process ID of the sender.
    • UID: The User ID (e.g., 1000).
    • GID: The Group ID.
  • Why it’s special: The sender claims they are PID 1234, but the Linux Kernel overwrites the message with the truth. The receiver can trust this data 100% because it comes from the kernel.
  • Use Case: A system daemon (like systemd or dbus) receives a request to restart a service. It uses SCM_CREDENTIALS to verify: "Is the process talking to me actually owned by root, or is it a random user trying to hack the system?"

SCM_SECURITY (The "Security Label")

This is used by Linux Security Modules (LSMs) like SELinux or AppArmor.

  • What it sends: The "Security Context" or label of the sending process.
  • Use Case: In high-security environments, the Gofer in gVisor might use this to verify the SELinux label of the Sentry. It ensures that not only is the process a Sentry, but it’s a Sentry with the specific restricted security profile expected.

SCM_TIMESTAMP (The "Postmark")

This provides a high-precision timestamp of exactly when a packet was received by the network stack.

  • What it sends: A struct timeval or timespec.
  • Use Case: This is critical for Precision Time Protocol (PTP) or high-frequency trading applications where every microsecond matters. It allows the application to know exactly when a message arrived at the hardware level, ignoring any delays caused by the CPU being busy.

SCM_TIMESTAMPING (The "Network Trace")

A more advanced version of the above.

  • What it sends: Three different timestamps: when the packet hit the physical hardware, when it entered the kernel, and when it was handed to the app.
  • Use Case: Deep network latency debugging.

Comparison: SCM_RIGHTS vs. The Others

SCM Type Action Kernel Role
SCM_RIGHTS Active. Modifies the receiver's FD table. Constructor. It builds a new handle.
SCM_CREDENTIALS Passive/Verify. Provides metadata. Witness. It verifies the sender's identity.
SCM_SECURITY Passive/Verify. Provides security labels. Auditor. It attaches the security context.
SCM_TIMESTAMP Informational. Provides timing. Clock. It stamps the message.

How they are sent (The msghdr Structure)

All SCM messages are sent using the sendmsg() and recvmsg() system calls. They aren't in the main "data buffer." Instead, they are placed in a special "Control Buffer."

If you were to look at the code of a container runtime, you would see it building a struct msghdr. Inside that structure is a pointer to the Ancillary Data. The kernel loops through that data and processes each SCM type one by one.

Summary: Why do we have these?

SCM messages exist because the data itself is not enough.

  • In a network packet, the data is just bytes.
  • In a Unix Socket, the kernel adds "Context" (Who sent it? When? With what handles?).

SCM_RIGHTS is the "Hand" that passes tools (FDs), while SCM_CREDENTIALS is the "ID Card" that shows who is holding the tools.