unshare(2)

๐Ÿ‘‘ unshare(2) โ€” the System Calls Manual, section 2, but make it fashion ๐Ÿฆ‹

okay so. unshare(2) is a system call manual page, and this is part one, bestie. grab a strawberry drink ๐Ÿ“ and let's go.


โœจ NAME โœจ

unshare โ€” disassociate parts of the process execution context

๐Ÿ“š LIBRARY ๐Ÿ“š

Standard C library (libc, -lc)

so no cap, it's just libc, nothing exotic ๐Ÿ’…

๐ŸŒˆ SYNOPSIS ๐ŸŒˆ

#define _GNU_SOURCE
#include <sched.h>

int unshare(int flags);

๐Ÿ’– DESCRIPTION ๐Ÿ’–

unshare() lets a process (or a thread, hi) disassociate parts of its execution context from the other processes (or threads) it's currently sharing them with. like, breaking up but politely โœจ

some parts of the execution context get shared implicitly when a new process is made with fork(2) or vfork(2) โ€” think the mount namespace, that vibe. other parts, like virtual memory, only get shared if you explicitly ask for it when you create a process or thread with clone(2).

the whole point of unshare(), its main character moment, is this: it lets a process take control of its shared execution context without having to spawn a whole new process. iconic behavior, honestly ๐Ÿ‘‘

the flags argument is a bit mask that says which parts of the execution context should get unshared. you build it by ORing together zero or more of these constants:

  • CLONE_FILES โ€” undoes what the clone(2) CLONE_FILES flag did. unshares the file descriptor table, so the calling process isn't sharing its file descriptors with any other process anymore. goodbye shared fds ๐Ÿซถ
  • CLONE_FS โ€” undoes the clone(2) CLONE_FS flag. unshares filesystem attributes, so the calling process stops sharing its root directory (chroot(2)), its current directory (chdir(2)), and its umask (umask(2)) attributes with any other process.
  • CLONE_NEWCGROUP (since Linux 4.6) โ€” does the same thing as the clone(2) CLONE_NEWCGROUP flag. unshares the cgroup namespace. using CLONE_NEWCGROUP requires the CAP_SYS_ADMIN capability. ๐Ÿ”
  • CLONE_NEWIPC (since Linux 2.6.19) โ€” same effect as the clone(2) CLONE_NEWIPC flag. unshares the IPC namespace, so the calling process gets a private copy of the IPC namespace that is not shared with any other process. specifying this flag automatically implies CLONE_SYSVSEM too. using CLONE_NEWIPC requires the CAP_SYS_ADMIN capability.
  • CLONE_NEWNET (since Linux 2.6.24) โ€” same effect as the clone(2) CLONE_NEWNET flag. unshares the network namespace, so the calling process moves into a brand new network namespace that isn't shared with any previously existing process. using CLONE_NEWNET requires the CAP_SYS_ADMIN capability.
  • CLONE_NEWNS โ€” same effect as the clone(2) CLONE_NEWNS flag. unshares the mount namespace, so the calling process has a private copy of its namespace that's not shared with any other process. specifying this flag automatically implies CLONE_FS too. using CLONE_NEWNS requires the CAP_SYS_ADMIN capability. for more info, go see mount_namespaces(7).
  • CLONE_NEWPID (since Linux 3.8) โ€” same effect as the clone(2) CLONE_NEWPID flag. unshares the PID namespace, so the calling process gets a new PID namespace for its children that isn't shared with any previously existing process. the calling process itself is not moved into the new namespace (read that twice, bestie, it trips people up ๐Ÿ˜ญ). the first child created by the calling process will have process ID 1 and will take on the role of init(1) in the new namespace. CLONE_NEWPID automatically implies CLONE_THREAD too. using CLONE_NEWPID requires the CAP_SYS_ADMIN capability. for more, see pid_namespaces(7).
  • CLONE_NEWTIME (since Linux 5.6) โ€” unshares the time namespace, so the calling process gets a new time namespace for its children that isn't shared with any previously existing process. again, the calling process is not moved into the new namespace. using CLONE_NEWTIME requires the CAP_SYS_ADMIN capability. for more, see time_namespaces(7). ๐Ÿ•ฐ๏ธ
  • CLONE_NEWUSER (since Linux 3.8) โ€” same effect as the clone(2) CLONE_NEWUSER flag. unshares the user namespace, so the calling process is moved into a new user namespace that isn't shared with any previously existing process. just like the child process made by clone(2) with the CLONE_NEWUSER flag, the caller gets a full set of capabilities in the new namespace. slay? slay. ๐Ÿ’…

CLONE_NEWUSER requires that the calling process is not threaded; specifying CLONE_NEWUSER automatically implies CLONE_THREAD. since Linux 3.9, CLONE_NEWUSER also automatically implies CLONE_FS. CLONE_NEWUSER requires that the user ID and group ID of the calling process are mapped to user IDs and group IDs in the user namespace of the calling process at the time of the call.

for further info on user namespaces, see user_namespaces(7).

  • CLONE_NEWUTS (since Linux 2.6.19) โ€” same effect as the clone(2) CLONE_NEWUTS flag. unshares the UTS IPC namespace, so the calling process gets a private copy of the UTS namespace that isn't shared with any other process. using CLONE_NEWUTS requires the CAP_SYS_ADMIN capability.
  • CLONE_SYSVSEM (since Linux 2.6.26) โ€” this flag reverses the effect of the clone(2) CLONE_SYSVSEM flag. unshares System V semaphore adjustment (semadj) values, so the calling process gets a new empty semadj list that isn't shared with any other process. if this is the last process holding a reference to the process's current semadj list, then the adjustments in that list get applied to the corresponding semaphores, exactly as described in semop(2).

and one more thing, bestie:

CLONE_THREAD, CLONE_SIGHAND, and CLONE_VM can also be passed in flags โ€” but only if the caller is single threaded (meaning it is not sharing its address space with another process or thread). in that case, these flags have no effect at all. (also note that specifying CLONE_THREAD automatically implies CLONE_VM, and specifying CLONE_VM automatically implies CLONE_SIGHAND.) if the process is multithreaded, then using these flags results in an error. ๐Ÿซ 

and if flags is specified as zero, then unshare() is a no-op โ€” zero changes to the calling process's execution context. it's giving "we're not doing anything today" ๐Ÿ˜Œ


๐ŸŽ€ RETURN VALUE ๐ŸŽ€

on success, zero is returned. on failure, -1 is returned and errno is set to say what went wrong.


๐Ÿ’€ ERRORS ๐Ÿ’€

  • EINVAL โ€” an invalid bit was specified in flags.
  • EINVAL โ€” CLONE_THREAD, CLONE_SIGHAND, or CLONE_VM was specified in flags, and the caller is multithreaded.
  • EINVAL โ€” CLONE_NEWIPC was specified in flags, but the kernel was not configured with the CONFIG_SYSVIPC and CONFIG_IPC_NS options.
  • EINVAL โ€” CLONE_NEWNET was specified in flags, but the kernel was not configured with the CONFIG_NET_NS option.
  • EINVAL โ€” CLONE_NEWPID was specified in flags, but the kernel was not configured with the CONFIG_PID_NS option.
  • EINVAL โ€” CLONE_NEWUSER was specified in flags, but the kernel was not configured with the CONFIG_USER_NS option.
  • EINVAL โ€” CLONE_NEWUTS was specified in flags, but the kernel was not configured with the CONFIG_UTS_NS option.
  • EINVAL โ€” CLONE_NEWPID was specified in flags, but the process has previously called unshare() with the CLONE_NEWPID flag. (you only get the one, babe ๐Ÿšซ)
  • ENOMEM โ€” cannot allocate sufficient memory to copy parts of the caller's context that need to be unshared.
  • ENOSPC (since Linux 3.7) โ€” CLONE_NEWPID was specified in flags, but the limit on the nesting depth of PID namespaces would have been exceeded; see pid_namespaces(7).
  • ENOSPC (since Linux 4.9; beforehand EUSERS) โ€” CLONE_NEWUSER was specified in flags, and the call would cause the limit on the number of nested user namespaces to be exceeded. see user_namespaces(7).

from Linux 3.11 to Linux 4.8, the error diagnosed in this case was EUSERS.

  • ENOSPC (since Linux 4.9) โ€” one of the values in flags specified the creation of a new user namespace, but doing so would have caused the limit defined by the corresponding file in /proc/sys/user to be exceeded. for further details, see namespaces(7).
  • EPERM โ€” the calling process did not have the required privileges for this operation.
  • EPERM โ€” CLONE_NEWUSER was specified in flags, but either the effective user ID or the effective group ID of the caller does not have a mapping in the parent namespace (see user_namespaces(7)).
  • EPERM (since Linux 3.9) โ€” CLONE_NEWUSER was specified in flags and the caller is in a chroot environment (i.e., the caller's root directory does not match the root directory of the mount namespace in which it resides).
  • EUSERS (from Linux 3.11 to Linux 4.8) โ€” CLONE_NEWUSER was specified in flags, and the limit on the number of nested user namespaces would be exceeded. see the discussion of the ENOSPC error above. โ†‘

and that's a wrap on part one, bestie ๐Ÿงš there's still STANDARDS, HISTORY, and NOTES waiting for you in part two, so don't go anywhere ๐Ÿ’œ

โœจ EXAMPLES โœจ

Okay bestie, here's a whole lil' baby program that basically is unshare(1) โ€” it unshares one or more namespaces and then runs whatever command you threw at it in its command-line arguments. So cute, so powerful. ๐Ÿ’…

Here's how you'd use it, running a shell inside a brand new mount namespace and then checking that the OG shell and the new shell are living in separate mount namespaces like the independent queens they are:

$ readlink /proc/$$/ns/mnt;
mnt:[4026531840]
$ sudo ./unshare -m /bin/bash;
# readlink /proc/$$/ns/mnt;
mnt:[4026532325]

See how those two readlink(1) calls gave back different stuff? That's the whole point, bestie โ€” it shows the two shells are in different mount namespaces. Not me getting emotional over mnt:[4026531840] vs mnt:[4026532325]. ๐Ÿ˜ญโœจ

๐Ÿ’– Program source ๐Ÿ’–

/* unshare.c

   A simple implementation of the unshare(1) command: unshare
   namespaces and execute a command.
*/
#define _GNU_SOURCE
#include <err.h>
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

static void
usage(char *pname)
{
    fprintf(stderr, "Usage: %s [options] program [arg...]\n", pname);
    fprintf(stderr, "Options can be:\n");
    fprintf(stderr, "    -C   unshare cgroup namespace\n");
    fprintf(stderr, "    -i   unshare IPC namespace\n");
    fprintf(stderr, "    -m   unshare mount namespace\n");
    fprintf(stderr, "    -n   unshare network namespace\n");
    fprintf(stderr, "    -p   unshare PID namespace\n");
    fprintf(stderr, "    -t   unshare time namespace\n");
    fprintf(stderr, "    -u   unshare UTS namespace\n");
    fprintf(stderr, "    -U   unshare user namespace\n");
    exit(EXIT_FAILURE);
}

int
main(int argc, char *argv[])
{
    int flags, opt;

    flags = 0;

    while ((opt = getopt(argc, argv, "CimnptuU")) != -1) {
        switch (opt) {
        case 'C': flags |= CLONE_NEWCGROUP;     break;
        case 'i': flags |= CLONE_NEWIPC;        break;
        case 'm': flags |= CLONE_NEWNS;         break;
        case 'n': flags |= CLONE_NEWNET;        break;
        case 'p': flags |= CLONE_NEWPID;        break;
        case 't': flags |= CLONE_NEWTIME;       break;
        case 'u': flags |= CLONE_NEWUTS;        break;
        case 'U': flags |= CLONE_NEWUSER;       break;
        default:  usage(argv[0]);
        }
    }

    if (optind >= argc)
        usage(argv[0]);

    if (unshare(flags) == -1)
        err(EXIT_FAILURE, "unshare");

    execvp(argv[optind], &argv[optind]);
    err(EXIT_FAILURE, "execvp");
}

๐ŸŒˆ SEE ALSO ๐ŸŒˆ

Documentation/userspace-api/unshare.rst in the Linux kernel source tree


and that's a wrap bestie!! ๐ŸŽ€ you just read the whole Linux man-pages unshare(2) page โ€” version 6.20, dated 2026-02-08. go forth and unshare responsibly, mwah ๐Ÿ’‹๐Ÿฆ‹

๐Ÿ“ฆ where this page comes from
  • arch rolling: man-pages 6.20-1 ยท BSD-2-Clause AND BSD-3-Clause AND BSD-4.3TAHOE AND BSD-4-Clause-UC AND GPL-1.0-or-later AND GPL-2.0-only AND GPL-2.0-or-later AND GPL-3.0-or-later AND LGPL-3.0-linking-exception AND LGPL-3.0-or-later AND LicenseRef-Public-Domain AND LicenseRef-UltraPermissive AND Linux-man-pages-1-para AND Linux-man-pages-copyleft AND Linux-man-pages-copyleft-2-para AND Linux-man-pages-copyleft-var AND MIT AND Spencer-94
  • nixpkgs unstable: man-pages 6.20
  • ๐Ÿ“œ the page's license: GPL-1.0-or-later
  • ๐Ÿ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms