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 theclone(2)CLONE_FILESflag 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 theclone(2)CLONE_FSflag. 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 theclone(2)CLONE_NEWCGROUPflag. unshares the cgroup namespace. usingCLONE_NEWCGROUPrequires theCAP_SYS_ADMINcapability. ๐CLONE_NEWIPC(since Linux 2.6.19) โ same effect as theclone(2)CLONE_NEWIPCflag. 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 impliesCLONE_SYSVSEMtoo. usingCLONE_NEWIPCrequires theCAP_SYS_ADMINcapability.CLONE_NEWNET(since Linux 2.6.24) โ same effect as theclone(2)CLONE_NEWNETflag. unshares the network namespace, so the calling process moves into a brand new network namespace that isn't shared with any previously existing process. usingCLONE_NEWNETrequires theCAP_SYS_ADMINcapability.CLONE_NEWNSโ same effect as theclone(2)CLONE_NEWNSflag. 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 impliesCLONE_FStoo. usingCLONE_NEWNSrequires theCAP_SYS_ADMINcapability. for more info, go seemount_namespaces(7).CLONE_NEWPID(since Linux 3.8) โ same effect as theclone(2)CLONE_NEWPIDflag. 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 ID1and will take on the role ofinit(1)in the new namespace.CLONE_NEWPIDautomatically impliesCLONE_THREADtoo. usingCLONE_NEWPIDrequires theCAP_SYS_ADMINcapability. for more, seepid_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. usingCLONE_NEWTIMErequires theCAP_SYS_ADMINcapability. for more, seetime_namespaces(7). ๐ฐ๏ธCLONE_NEWUSER(since Linux 3.8) โ same effect as theclone(2)CLONE_NEWUSERflag. 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 byclone(2)with theCLONE_NEWUSERflag, 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 theclone(2)CLONE_NEWUTSflag. 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. usingCLONE_NEWUTSrequires theCAP_SYS_ADMINcapability.CLONE_SYSVSEM(since Linux 2.6.26) โ this flag reverses the effect of theclone(2)CLONE_SYSVSEMflag. unshares System V semaphore adjustment (semadj) values, so the calling process gets a new emptysemadjlist that isn't shared with any other process. if this is the last process holding a reference to the process's currentsemadjlist, then the adjustments in that list get applied to the corresponding semaphores, exactly as described insemop(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, orCLONE_VMwas specified in flags, and the caller is multithreaded.EINVALโCLONE_NEWIPCwas specified in flags, but the kernel was not configured with theCONFIG_SYSVIPCandCONFIG_IPC_NSoptions.EINVALโCLONE_NEWNETwas specified in flags, but the kernel was not configured with theCONFIG_NET_NSoption.EINVALโCLONE_NEWPIDwas specified in flags, but the kernel was not configured with theCONFIG_PID_NSoption.EINVALโCLONE_NEWUSERwas specified in flags, but the kernel was not configured with theCONFIG_USER_NSoption.EINVALโCLONE_NEWUTSwas specified in flags, but the kernel was not configured with theCONFIG_UTS_NSoption.EINVALโCLONE_NEWPIDwas specified in flags, but the process has previously calledunshare()with theCLONE_NEWPIDflag. (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_NEWPIDwas specified in flags, but the limit on the nesting depth of PID namespaces would have been exceeded; seepid_namespaces(7).ENOSPC(since Linux 4.9; beforehandEUSERS) โCLONE_NEWUSERwas specified in flags, and the call would cause the limit on the number of nested user namespaces to be exceeded. seeuser_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/userto be exceeded. for further details, seenamespaces(7).EPERMโ the calling process did not have the required privileges for this operation.EPERMโCLONE_NEWUSERwas 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 (seeuser_namespaces(7)).EPERM(since Linux 3.9) โCLONE_NEWUSERwas specified in flags and the caller is in achrootenvironment (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_NEWUSERwas specified in flags, and the limit on the number of nested user namespaces would be exceeded. see the discussion of theENOSPCerror 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
- Copyright 2006, Janak Desai <janak@us.ibm.com>
- Copyright 2006-2012, Michael Kerrisk <mtk.manpages@gmail.com>
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms