Skip to content

Privilege Separation

Daniel Wagner edited this page Oct 13, 2026 · 2 revisions

Privilege Separation

Privilege separation is a planned change to how nvme-cli runs. Only a small helper process keeps root privileges. All other code runs without them.

This is a design draft. Privilege separation itself is not implemented yet. The preparation in the plugins is done in nvme-cli 3.2 (unreleased). The feature is planned for a later 3.x release. The design is discussed in issue #3879. Comments there are welcome.

Why does it exist?

Today, nvme-cli runs as one process. This process usually runs as root. It does two kinds of work:

  • It talks to the kernel. It issues passthru ioctls and writes to /dev/nvme-fabrics. This needs root.
  • It parses arguments and nvme-fabrics.conf, decodes the data that the drive returns, and prints it as text or JSON. All vendor plugins do this too. This does not need root.

The second part is much larger. A bug there runs with full root privileges. A drive that returns crafted or broken data can trigger such a bug.

Privilege separation moves the second part out of the root process.

How it works

At startup, nvme-cli forks into two processes. They talk over a socket pair.

  • The parent does all parsing, decoding and printing. It drops to the real user and group ID right after the fork.
  • The child is the privileged helper. It does exactly one thing: it issues the ioctl or the fabrics connect write. It returns the raw result to the parent. It does not interpret the data.

The helper is hardened:

  • It only opens /dev/nvme<N>, /dev/nvme<N>n<M> or /dev/nvme-fabrics.
  • It drops all capabilities except CAP_SYS_ADMIN.
  • A seccomp filter allows only ioctl, read, write, close and exit_group.

The helper exists only while the nvme-cli command runs. It is not a daemon.

What changes for users

Nothing changes by default. Privilege separation is off unless your distribution enables it.

A distribution enables it with the installation. It installs the helper with file capabilities or setuid root. This choice is not decided yet.

When privilege separation is not enabled, nvme-cli uses the direct ioctl path as today. This also applies when you already run nvme-cli as root.

Privilege separation does not limit what you can do with the drive. A user who can run nvme-cli can still run sanitize, format, security-send or firmware commands. It only limits which code runs with root privileges.

What changes for plugin authors

Nothing, for most plugins. All passthru commands go through libnvme_exec_admin_passthru() and libnvme_exec_io_passthru(). These functions send the command to the helper.

Do not call ioctl() directly on the file descriptor from libnvme_transport_handle_get_fd(). With privilege separation, this function returns LIBNVME_INVALID_FD. Use the libnvme API instead.

The design named two plugins that called raw ioctls. Both are fixed in nvme-cli 3.2 (unreleased) as a preparation for privilege separation:

  • plugins/sed: uses the new libnvme sed module (libnvme-sed.h) for level 0 discovery and Opal operations.
  • plugins/scaleflux: uses libnvme calls instead of block device ioctls. The ScaleFlux proprietary ioctls are removed. Because of this, the clean card feature is gone, and CSD 2000 drives with the proprietary driver are no longer supported.

No plugin issues raw device ioctls now.

What changes for libnvme users

Nothing. The change adds new symbols only. The existing API and ABI do not change. The library SONAME does not change.

Current limits

  • Not implemented yet. Only the preparation in the plugins is done.
  • The packaging method (file capabilities, setuid root or polkit) is not decided.
  • Large transfers, for example telemetry logs, need a larger buffer limit. The limit is not decided yet.

See also

Clone this wiki locally