Deep Dive into unshare: Exploring Linux Namespace Isolation

Screenshot of unshare help output

In our previous post on Linux namespaces, we explored the foundational concepts that enable process-level isolation on Linux systems. Today, we’re taking a deeper look at one of the most powerful tools available for working directly with namespaces: the unshare command.

This post is intended for system administrators, developers, and enthusiasts who want to go beyond container runtimes and understand how namespaces are manipulated directly. We’ll explore what unshare is, how it works under the hood, common and advanced usage patterns, edge cases, and the limitations of namespace isolation.


What is unshare?

unshare is a command-line utility that allows you to run a program with one or more Linux namespaces unshared from the parent process. In simpler terms, it lets you create a new isolated environment by selectively detaching system resources (like mount points, networking, or user IDs) from the rest of the system.

Under the hood, unshare uses the unshare(2) system call to reconfigure the calling process's namespace associations. This is foundational in building containers, sandboxing environments, and simulating isolated systems for development and testing.


Supported Namespace Types

You can unshare any of the following namespace types using unshare:

FlagNamespaceIsolates
--mountmntMount points (e.g., filesystems)
--utsutsHostname and domain name
--ipcipcSystem V IPC, message queues
--netnetNetwork interfaces and routing tables
--pidpidProcess ID tree
--useruserUser/group ID mappings
--cgroupcgroupControl group hierarchies
--timetimeSystem clocks (monotonic and boot)

Real-World Examples: Practical Use Cases for unshare

Example 1: Isolate a Custom Hostname for a Service

sudo unshare --uts --hostname=metrics-sandbox bash
hostname

Useful when testing applications that depend on hostname values or domain naming conventions, such as telemetry collectors.


Example 2: Isolated Mount Namespace for a Secure Chroot

sudo unshare --mount bash
mount --make-rprivate /
mkdir /mnt/test
mount -t tmpfs tmpfs /mnt/test
cd /mnt/test
touch isolated.txt

This allows temporary or sensitive mounts (e.g., encrypted tmpfs, ephemeral dev roots) without leaking them into the global mount table.


Example 3: Full User, PID, and Mount Isolation for a Build Sandbox

unshare --user --map-root-user --mount --pid --fork bash
id
ps aux

Ideal for creating a root-like build environment for software compilation or test execution, while being isolated from host users and processes.


Example 4: Isolated Network Namespace for Custom Routing

Let’s say you want to route traffic from a specific tool through a VPN without affecting the host:

sudo unshare --net --uts bash
ip link add veth0 type veth peer name veth1
ip link set veth0 up
ip addr add 10.200.1.1/24 dev veth0

# Move veth1 to host netns and link to VPN interface
ip link set veth1 netns 1
ip netns exec 1 ip link set veth1 up
brctl addbr br0
brctl addif br0 veth1

You can now run applications in this isolated namespace and direct their traffic through specialized routing rules or firewall settings.


Internals: How unshare Works

  1. The process calls unshare(2) with namespace flags.
  2. Kernel allocates new namespace objects.
  3. Process is re-associated with these namespaces.
  4. Any children forked after this will inherit the same namespace context.

Namespaces are represented in /proc/<pid>/ns/ and are referenced by file descriptors. This allows creative compositions, like passing namespaces between processes or reattaching to an existing one using setns(2).


Observing Namespaces and Using nsenter

You can inspect the namespaces a process belongs to:

readlink /proc/$$/ns/*

To enter another process's namespace:

sudo nsenter --target <pid> --net --uts --ipc --mount bash

This is useful for debugging or "breaking into" container environments.


Shared Kernel Resources and Namespace Limitations

While namespaces isolate many aspects of the system, some kernel resources remain global:

  • Firewall rules: Tools like iptables, nftables, and ebtables often remain shared across network namespaces. Although nftables supports per-namespace tables via hooks, firewall changes can still impact all namespaces unless carefully segmented.
  • Sysctl knobs: Many kernel tunables under /proc/sys/ are global, including network-level controls unless overridden via netns-aware sysctls.
  • Security Modules (SELinux/AppArmor): These operate at the kernel level and require explicit policies to be aware of namespace contexts.
  • Devices: /dev access and device nodes are shared unless hidden or filtered via mount namespaces or cgroup device controllers.
  • /sys and /proc: Only some views are namespace-aware. For full process or mount isolation, combine pid, mnt, and user namespaces.

Common Use Cases for unshare

  • Building minimal, container-like sandboxes without Docker
  • Creating ephemeral test environments
  • Learning kernel internals interactively
  • Custom VPN routing or traffic capture setups
  • Building isolated CI/CD runners

Conclusion

unshare is more than just a niche debugging tool—it’s a direct gateway into the kernel features powering container platforms, virtualization technologies, and security sandboxes. By mastering unshare, you gain a deeper understanding of how Linux isolates workloads and how you can leverage it for testing, debugging, or crafting minimal, secure environments.

It also surfaces the boundaries of namespace isolation: while powerful, some kernel resources remain shared unless further mitigated with seccomp, cgroups, or kernel patching.

Stay tuned for our next post where we use unshare, pivot_root, and mount to build a container from first principles—no Docker, no LXD, just pure Linux isolation.


Experiment carefully, especially with mount and network namespaces. And remember, you can always use lsns, nsenter, and /proc/<pid>/ns/ to peek under the hood.