Skip to content
/linux-syscalls

Namespaces & Containers · Section 2

setns(2)

Move the calling thread into an existing namespace identified by a file descriptor.

Signature

#include <sched.h>

int setns(int fd, int nstype);
fd
Descriptor referring to a namespace. From /proc/<pid>/ns/<type>, or a pidfd (since 5.8).
nstype
0 to accept any namespace type, or one of CLONE_NEWNS / CLONE_NEWUSER / CLONE_NEWPID / CLONE_NEWNET / CLONE_NEWUTS / CLONE_NEWIPC / CLONE_NEWCGROUP / CLONE_NEWTIME to require that specific type. The latter is the safer pattern.

Description

setns() reassociates the calling thread with the namespace referred to by fd. fd is typically obtained by open()ing one of the /proc/<pid>/ns/* files (mnt, pid, net, user, ipc, uts, cgroup, time) or by pidfd_open() + the new setns(pidfd, CLONE_NEW*) form (Linux 5.8+). nstype is either 0 (kernel infers from the fd type) or one of the CLONE_NEW* constants (acts as a safety check — the call fails if fd doesn't match). The caller must have CAP_SYS_ADMIN in the target namespace's user namespace (CAP_SYS_CHROOT for mount namespaces); user-namespace transitions follow stricter rules (the new userns must be a descendant of the current one, or the caller must hold privilege in the parent). setns() is the syscall behind nsenter(1) and behind every 'docker exec' implementation.

Architecture mapping

ArchitectureNumberABIEntry point
x86 (i386)346i386sys_setns
x64 (x86_64)308commonsys_setns
ARM64 (aarch64)268sys_setns

Kernel history

Introduced in Linux 3.0.

  1. 3.0

    setns() was introduced in 3.0 alongside the broader user/mount/pid namespace tooling that turned earlier kernel work into a coherent toolkit usable from userspace (nsenter, ip netns, container runtimes).

  2. 5.8

    setns() was extended to accept a pidfd (from pidfd_open() or clone(CLONE_PIDFD)) and a bitmask of CLONE_NEW* flags, so a caller can atomically enter multiple namespaces of a target process without opening individual /proc/<pid>/ns/* files. Required for race-free 'enter every namespace of this process' patterns used by modern container tooling.

seccomp & containers

Docker default profile

Blocked

Podman default profile

Blocked

setns() is BLOCKED by default in Docker and Podman, with good reason: allowing it lets a workload jump into namespaces it shouldn't see, including the host namespaces if any are reachable (e.g. through a misconfigured /proc bind-mount). Enable it only for container-management workloads (the docker engine itself, kubelet) — never for application workloads.

libseccomp

// setns() is NOT on the Docker default allow-list.
seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(setns), 0);

strace example

$ strace -e setns nsenter -t 1 -m /bin/ls /proc 2>&1 | head -3
setns(3, CLONE_NEWNS)                   = 0

setns() with a /proc/<pid>/ns/<type> fd opened just before is the canonical trace pattern. -y resolves the fd to the namespace path, making the trace self-explanatory. nsenter's source is straightforward to read alongside the strace output if you want to understand the full setns sequence.

Security & observability

setns() to /proc/1/ns/mnt is the canonical container-escape primitive — if a workload can reach a file descriptor for the host's PID-1 mount namespace, calling setns() puts it in the host's mount namespace, where it can see and modify any host file. Most escape chains route through this. Mitigations: don't bind-mount /proc into containers, drop CAP_SYS_ADMIN, deny setns() in seccomp (the default). eBPF tracepoint sys_enter_setns is a high-precision signal — any call from a non-init container PID is alert-worthy. From the inside, comparing /proc/self/ns/<type> readlinks against the expected container namespace inodes detects post-hoc escape.

Errors

EBADF
fd is not a valid descriptor or does not refer to a namespace.
EINVAL
nstype doesn't match the fd's actual namespace type, or the namespace type is not supported by the running kernel.
ENOMEM
Insufficient kernel memory.
EPERM
Caller lacks CAP_SYS_ADMIN in the target namespace's user namespace, or the requested userns transition violates the parent-descendant rule.

Related syscalls