Skip to content

AI Networking Security · Part 2 of 9

Act 2 — RoCEv2 Memory Region and RKEY Security

Understanding RKEY security requires understanding how Memory Regions work at the libibverbs API level — because the security boundary is defined there, not in the network.

Memory Region registration

When an application calls ibv_reg_mr(), it registers a region of virtual memory with the NIC. The NIC pins those pages in physical memory (preventing the OS from swapping them out) and records the access permissions:

struct ibv_mr *mr = ibv_reg_mr(
    pd,                          // Protection Domain: which QPs can use this MR
    buffer,                      // virtual address of the memory region
    buffer_size,                 // length in bytes
    IBV_ACCESS_LOCAL_WRITE |     // this QP can write
    IBV_ACCESS_REMOTE_READ  |    // remote QPs can read (requires RKEY)
    IBV_ACCESS_REMOTE_WRITE      // remote QPs can write (requires RKEY)
);

// After registration:
// mr->lkey = local key  (used by local QPs to reference this MR)
// mr->rkey = remote key (must be shared with remote side for RDMA access)

The pd (Protection Domain) scopes which local QPs can use this MR. But the RKEY is different — it is a token that must be communicated out-of-band (typically through the connection setup exchange in the application protocol) to the remote side. Once the remote side has the RKEY, they can issue RDMA Read or Write operations against this MR without any further participation from the local node's OS.

The RKEY entropy problem

RKEYs are 32-bit values. On a correctly implemented system, they should be cryptographically random — an attacker would need to try up to 4 billion values to guess one. In practice, several Linux kernel versions initialised the RKEY counter from a low-entropy seed, resulting in the first RKEY allocated on a freshly booted node being a small, predictable value (often in the range 0x00000001–0x000000FF).

An attacker with network access to the target node and no GID filtering blocking their QP connection can scan this range in milliseconds. With a 400GbE RDMA link, a scan of 256 RKEY values completes in under 100 microseconds. A successful hit gives full read access to whatever that MR contains — GPU gradient tensors, model weights, dataset batches.

# Check RKEY entropy on a live system by reading the MR info:
# (from the local node)
python3 -c "
import subprocess
result = subprocess.run(['ibv_reg_mr_test'], capture_output=True, text=True)
print(result.stdout)
# Look for: rkey=0x00000027  <-- suspiciously low = low entropy
# Healthy:  rkey=0xA7F3C209  <-- high entropy = not guessable
"

# Kernel parameter that affects RKEY entropy:
# (set in /proc/sys/kernel/randomize_va_space)
# Value 0 = no ASLR = RKEY seed also predictable
# Value 2 = full ASLR = RKEY generation uses higher entropy
cat /proc/sys/kernel/randomize_va_space

RKEY rotation as mitigation

Deregistering and re-registering a Memory Region forces the kernel to assign a new RKEY. If the new RKEY is drawn from a high-entropy pool, the old value — even if it was guessed by an attacker — becomes invalid immediately.

// Rotation sequence:
ibv_dereg_mr(mr);                // invalidates old RKEY immediately
mr = ibv_reg_mr(pd, buffer, buffer_size, access_flags);  // new RKEY assigned
// Share new mr->rkey with legitimate peers via your connection protocol

The window of vulnerability during rotation is the time between deregistration and re-registration — typically under 1 microsecond. Any in-flight RDMA operation using the old RKEY will receive IBV_WC_REM_ACCESS_ERR at completion.

GID filtering: the primary isolation mechanism

A GID (Global Identifier) is the InfiniBand/RoCEv2 equivalent of an IPv6 address for RDMA endpoints. By default on ConnectX-7, any remote GID can attempt to establish a QP connection. GID filtering restricts this: only GIDs on an administrator-controlled allow-list can establish QPs.

# Enable GID filtering on ConnectX-7:
mst start
mlxconfig -d /dev/mst/mt4129_pciconf0 s ROCE_ADDR_FILTER_ENABLE=1

# Verify:
mlxconfig -d /dev/mst/mt4129_pciconf0 q | grep ROCE_ADDR_FILTER
# Expected: ROCE_ADDR_FILTER_ENABLE=1

# Inspect current GID table:
ibv_devinfo -d mlx5_0 -i 1
# Shows GID entries — with filter enabled, only listed GIDs can connect

# View which GIDs are currently allowed:
rdma res show gid

With GID filtering active, a Tenant B node attempting to establish a QP to Tenant A will receive a connection refusal at the NIC ASIC level — before any RKEY exchange occurs. This eliminates the scanning threat entirely: no QP connection, no RKEY presentation, no RDMA access.