UNSHARE(1)

๐Ÿ‘‘ unshare โ€” run program in new namespaces ๐Ÿ‘‘

bestie we are SO back. this is the UNSHARE(1) page, straight outta the User Commands section, and it's about to be your new personality. no cap.


โœจ SYNOPSIS โœจ

unshare [options] [program [arguments]]

๐Ÿฆ‹ DESCRIPTION ๐Ÿฆ‹

okay so here's the whole vibe: the unshare command makes brand new namespaces (whichever ones you ask for with the command-line options below, she's very customizable) and then runs the program you gave her. and if you didn't give her a program? she just runs "${SHELL}" instead (default is /bin/sh). lowkey iconic of her.

by default, a new namespace only sticks around as long as it has member processes. that's the whole deal. BUT โ€” and this is the glow-up โ€” you can make a new namespace persistent even when it has zero member processes, by bind mounting /proc/pid/ns/type files to a filesystem path. and once a namespace is persistent like that, you can waltz right back into it later with nsenter(1) even after the program has fully dipped โœŒ๏ธ (the one exception: PID namespaces, which need a permanently running init process, sorry girl). and when you're done with a persistent namespace? unpersist it by using umount(8) to yeet the bind mount. check the EXAMPLES section for the tea.

also, unshare since util-linux version 2.36 uses /proc/[pid]/ns/pid_for_children and /proc/[pid]/ns/time_for_children files for persistent PID and TIME namespaces. heads up though: this change requires Linux kernel 4.17 or newer. no downgrades, bestie ๐Ÿ’…

the following types of namespaces can be created with unshare:

  • mount namespace โ€” mounting and unmounting filesystems will not affect the rest of the system, except for filesystems which are explicitly marked as shared (with mount --make-shared; peep /proc/self/mountinfo or findmnt -o+PROPAGATION for the shared flags). for further details, see mount_namespaces(7).

unshare since util-linux version 2.27 automatically sets propagation to private in a new mount namespace, to make sure that the new namespace is really, truly unshared. it's possible to disable this feature with option --propagation unchanged. note that private is the kernel default anyway. periodt.

  • UTS namespace โ€” setting hostname or domainname will not affect the rest of the system. for further details, see uts_namespaces(7).
  • IPC namespace โ€” the process will have an independent namespace for POSIX message queues as well as System V message queues, semaphore sets and shared memory segments. for further details, see ipc_namespaces(7).
  • network namespace โ€” the process will have independent IPv4 and IPv6 stacks, IP routing tables, firewall rules, the /proc/net and /sys/class/net directory trees, sockets, etc. for further details, see network_namespaces(7).
  • PID namespace โ€” children will have a distinct set of PID-to-process mappings from their parent. for further details, see pid_namespaces(7).
  • cgroup namespace โ€” the process will have a virtualized view of /proc/self/cgroup, and new cgroup mounts will be rooted at the namespace cgroup root. for further details, see cgroup_namespaces(7).
  • user namespace โ€” the process will have a distinct set of UIDs, GIDs and capabilities. for further details, see user_namespaces(7).
  • time namespace โ€” the process can have a distinct view of CLOCK_MONOTONIC and/or CLOCK_BOOTTIME which can be changed using /proc/self/timens_offsets. for further details, see time_namespaces(7).

๐Ÿ’… OPTIONS ๐Ÿ’…

  • -i, --ipc[=file] โ€” create a new IPC namespace. if file is specified, then the namespace is made persistent by creating a bind mount at file.
  • -m, --mount[=file] โ€” create a new mount namespace. if file is specified, then the namespace is made persistent by creating a bind mount at file. note that file must be located on a mount whose propagation type is not shared (or an error results, bestie, it's giving drama). use the command findmnt -o+PROPAGATION when you're not sure about the current setting. see also the examples below.
  • -n, --net[=file] โ€” create a new network namespace. if file is specified, then the namespace is made persistent by creating a bind mount at file.
  • -p, --pid[=file] โ€” create a new PID namespace. if file is specified, then the namespace is made persistent by creating a bind mount at file. (creation of a persistent PID namespace will fail if the --fork option is not also specified.) see also the --fork and --mount-proc options.
  • -u, --uts[=file] โ€” create a new UTS namespace. if file is specified, then the namespace is made persistent by creating a bind mount at file.
  • -U, --user[=file] โ€” create a new user namespace. if file is specified, then the namespace is made persistent by creating a bind mount at file.
  • -C, --cgroup[=file] โ€” create a new cgroup namespace. if file is specified, then the namespace is made persistent by creating a bind mount at file.
  • -T, --time[=file] โ€” create a new time namespace. if file is specified, then the namespace is made persistent by creating a bind mount at file. the --monotonic and --boottime options can be used to specify the corresponding offset in the time namespace.
  • -f, --fork โ€” fork the specified program as a child process of unshare rather than running it directly. this is useful when creating a new PID namespace. note that when unshare is waiting for the child process, it ignores SIGINT and SIGTERM and does not forward any signals to the child. it is necessary to send signals to the child process.
  • --forward-signals โ€” forward SIGTERM and SIGINT signals received by the parent unshare process to the child process. when this option is not specified, unshare ignores these signals while waiting for the child process to exit (that's the default behavior since util-linux 2.36). this allows the parent to remain alive while the child process handles the signals.

this option is useful when the parent unshare process will receive SIGTERM or SIGINT signals (like during system reboot or from a process manager), and you want the child process to be notified of graceful shutdown requests so it can do its cleanup. if your child process has signal handlers (shell trap handlers, for example), enabling this option lets them actually execute. ๐Ÿซถ

this option implies --fork.

  • --keep-caps โ€” when the --user option is given, ensure that capabilities granted in the user namespace are preserved in the child process.
  • --kill-child[=signame] โ€” when unshare terminates, have signame be sent to the forked child process. combined with --pid this allows for an easy and reliable killing of the entire process tree below unshare. if not given, signame defaults to SIGKILL. this option implies --fork.
  • --mount-proc[=mountpoint] โ€” just before running the program, mount the proc filesystem at mountpoint (default is /proc). this is useful when creating a new PID namespace. it also implies creating a new mount namespace, since the /proc mount would otherwise mess up existing programs on the system ๐Ÿ˜ญ. the new proc filesystem is explicitly mounted as private (with MS_PRIVATE|MS_REC).
  • --mount-binfmt[=mountpoint] โ€” just before running the program, mount the binfmt_misc filesystem at mountpoint (default is /proc/sys/fs/binfmt_misc). it also implies creating a new mount namespace, since the binfmt_misc mount would otherwise mess up existing programs on the system. the new binfmt_misc filesystem is explicitly mounted as private (with MS_PRIVATE|MS_REC).
  • --map-user uid|name โ€” run the program only after the current effective user ID has been mapped to uid. if this option is specified multiple times, the last occurrence takes precedence. this option implies --user.
  • --map-users inneruid:outeruid:count|auto|subids|all โ€” run the program only after the block of user IDs of size count beginning at outeruid has been mapped to the block of user IDs beginning at inneruid. this mapping is created with newuidmap(1) if unshare was run unprivileged. if the range of user IDs overlaps with the mapping specified by --map-user, then a "hole" will be removed from the mapping. this may result in the highest user ID of the mapping not being mapped. use --map-users multiple times to map more than one block of user IDs. the special value auto will map the first block of user IDs owned by the effective user from /etc/subuid to a block starting at user ID 0. the special value subids will identity map the same block. the special value all will create a pass-through map for every user ID available in the parent namespace. this option implies --user.

before util-linux version 2.39, this option expected a comma-separated argument of the form outeruid,inneruid,count but that format is now deprecated for consistency with the ordering used in /proc/[pid]/uid_map and the X-mount.idmap mount option.

  • --map-group gid|name โ€” run the program only after the current effective group ID has been mapped to gid. if this option is specified multiple times, the last occurrence takes precedence. this option implies --setgroups=deny and --user.
  • --map-groups innergid:outergid:count|auto|subids|all โ€” run the program only after the block of group IDs of size count beginning at outergid has been mapped to the block of group IDs beginning at innergid. this mapping is created with newgidmap(1) if unshare was run unprivileged. if the range of group IDs overlaps with the mapping specified by --map-group, then a "hole" will be removed from the mapping. this may result in the highest group ID of the mapping not being mapped. use --map-groups multiple times to map more than one block of group IDs. the special value auto will map the first block of user IDs owned by the effective user from /etc/subgid to a block starting at group ID 0. the special value subids will identity map the same block. the special value all will create a pass-through map for every group ID available in the parent namespace. this option implies --user.

before util-linux version 2.39, this option expected a comma-separated argument of the form outergid,innergid,count but that format is now deprecated for consistency with the ordering used in /proc/[pid]/gid_map and the X-mount.idmap mount option.

  • --map-auto โ€” map the first block of user IDs owned by the effective user from /etc/subuid to a block starting at user ID 0. in the same manner, also map the first block of group IDs owned by the effective group from /etc/subgid to a block starting at group ID 0. this option is intended to handle the common case where the first block of subordinate user and group IDs can map the whole user and group ID space. this option is equivalent to specifying --map-users=auto and --map-groups=auto.
  • --map-subids โ€” maps the first block of user IDs that the effective user owns in /etc/subuid straight through as an identity map. And bestie, it does the exact same thing for groups: the first block of group IDs owned by the effective group in /etc/subgid gets identity mapped too. It's literally just shorthand for --map-users=subids plus --map-groups=subids. Two-for-one deal, we love efficiency ๐Ÿ’…
  • -r, --map-root-user โ€” the moment you've been waiting for: your program only runs after the current effective user and group IDs have been mapped to the superuser UID and GID inside the brand-new user namespace. Why do you care? Because it lets you (an unprivileged lil bean) conveniently grab the capabilities you need to actually manage stuff in the new namespaces โ€” like configuring interfaces in the network namespace or mounting filesystems in the mount namespace. Yes, even unprivileged. Iconic. ๐ŸŽ€
Lowkey a "mere convenience feature" though, no cap โ€” it does not support the more sophisticated use cases, like mapping multiple ranges of UIDs and GIDs. Know its limits bestie.

It implies --setgroups=deny and --user. It is equivalent to --map-user=0 --map-group=0.

  • -c, --map-current-user โ€” same energy, different flavor: the program runs only after the current effective user and group IDs get mapped to the same UID and GID in the newly created user namespace. Also implies --setgroups=deny and --user. It is equivalent to --map-user=$(id -ru) --map-group=$(id -rg).
  • --owner uid:gid โ€” sets the owner user and group when the user namespace is created. These decide which user over in the parent namespace holds CAP_SYS_ADMIN in the shiny new child namespace and can setns(2) into it. The vibe: a privileged user creates a namespace on behalf of an unprivileged one, using their own privileges to map ids and/or bind mount the namespace into the filesystem. It implies --user. ๐Ÿ‘‘
  • --propagation private|shared|slave|unchanged โ€” recursively sets the mount propagation flag in the new mount namespace. Default behavior is to set the propagation to private. You can turn the whole feature off by passing unchanged. And heads up: this option is silently ignored when the mount namespace (--mount) isn't even requested. Rude but true. ๐Ÿ™ˆ
  • --setgroups allow|deny โ€” allow or deny the setgroups(2) system call inside a user namespace.

Okay so here's the tea โ˜• โ€” to be able to call setgroups(2), the calling process must at least have CAP_SETGID. But since Linux 3.19 there's an extra restriction on top: the kernel only gives permission to call setgroups(2) after the GID map (/proc/pid*/gid_map*) has been set. The GID map is writable by root when setgroups(2) is enabled (that's allow, the default), and the GID map becomes writable by unprivileged processes only when setgroups(2) is permanently disabled (with deny).

  • -R, --root dir โ€” runs the command with root directory set to dir.
  • -w, --wd dir โ€” changes the working directory to dir.
  • -S, --setuid uid โ€” sets the user ID that will be used inside the namespace you enter.
  • -G, --setgid gid โ€” sets the group ID that will be used inside the namespace you enter, and drops supplementary groups. Bye besties ๐Ÿ‘‹
  • -l, --load-interp string โ€” loads a binfmt_misc definition inside the namespace (implies --mount-binfmt). The string argument is :name:type:offset:magic:mask:interpreter:flags. Want the full rundown on new binary type registration? It's over here: https://www.kernel.org/doc/Documentation/admin-guide/binfmt-misc.rst

And for the specifics: to manage the F flag in flags together with the --root parameter, binfmt_misc gets mounted twice โ€” once before the chroot, to load the interpreter from the caller filesystem, and once after, to make it available from the chroot userspace. โœจ

  • --monotonic offset โ€” sets the offset of CLOCK_MONOTONIC that'll be used in the time namespace you enter. Requires unsharing a time namespace with --time.
  • --boottime offset โ€” sets the offset of CLOCK_BOOTTIME that'll be used in the time namespace you enter. Also requires unsharing a time namespace with --time.
  • -h, --help โ€” displays the help text and dips. ๐Ÿซถ
  • -V, --version โ€” displays the version and dips.

๐Ÿ“ NOTES ๐Ÿ“

Okay, this part is important, don't scroll past it ๐Ÿ˜ญ

The proc and sysfs filesystems that get mounted as root inside a user namespace have to be restricted, so that a less privileged user can't just waltz in and get more access to sensitive files that a more privileged user made unavailable. Long story short, the rule for proc and sysfs is: keep it as close to a bind mount as possible. Periodt.


โœจ EXAMPLES โœจ

Bestie, this is the fun part. Let's actually do things. ๐Ÿ’–

The command below creates a PID namespace, using --fork to make sure the executed command runs in a child process that โ€” being the very first process in the namespace โ€” has PID 1. The --mount-proc option makes sure a new mount namespace is created at the same time, and that a fresh proc(5) filesystem gets mounted with the info corresponding to the new PID namespace. And the second readlink(1) finishes? The new namespaces get torn down automatically. Slay.

# unshare --fork --pid --mount-proc readlink /proc/self
1

As an unprivileged user, create a new user namespace where the user's credentials are mapped to the root IDs inside the namespace:

$ id -u; id -g
1000
1000
$ unshare --user --map-root-user \
        sh -c 'whoami; cat /proc/self/uid_map /proc/self/gid_map'
root
         0       1000          1
         0       1000          1

As an unprivileged user, create a user namespace where the first 65536 IDs are all mapped, and the user's credentials are mapped to the root IDs inside the namespace. The map is determined by the subordinate IDs assigned in subuid(5) and subgid(5). To demonstrate, we create a file with user ID 1 and group ID 1. For brevity, only the user ID mappings are shown:

$ id -u
1000
$ cat /etc/subuid
1000:100000:65536
$ unshare --user --map-auto --map-root-user
# id -u
0
# cat /proc/self/uid_map
         0       1000          1
         1     100000      65535
# touch file; chown 1:1 file
# ls -ln --time-style=+ file
-rw-r--r-- 1 1 1 0  file
# exit
$ ls -ln --time-style=+ file
-rw-r--r-- 1 100000 100000 0  file

The first of the following commands creates a new persistent UTS namespace and changes the hostname as seen in that namespace. Then we enter it with nsenter(1) to show off the modified hostname โ€” which proves the UTS namespace keeps existing even though it had zero member processes after the unshare command finished. Then we destroy the whole thing by removing the bind mount. Main character exit. ๐Ÿ’…

# touch /root/uts-ns
# unshare --uts=/root/uts-ns hostname FOO
# nsenter --uts=/root/uts-ns hostname
FOO
# umount /root/uts-ns

These commands set up a persistent mount namespace referenced by the bind mount /root/namespaces/mnt. To make sure creating that bind mount actually succeeds, the parent directory (/root/namespaces) is made into a bind mount whose propagation type is not shared:

# mount --bind /root/namespaces /root/namespaces
# mount --make-private /root/namespaces
# touch /root/namespaces/mnt
# unshare --mount=/root/namespaces/mnt

Now, the drama ๐Ÿ˜ค โ€” these commands demonstrate the --kill-child option when creating a PID namespace, making sure that when unshare gets killed, all the processes inside the PID namespace go down with it:

# set +m                # Don't print job status messages

# unshare --pid --fork --mount-proc --kill-child -- \
       bash --norc -c '(sleep 555 &) && (ps a &) && sleep 999' &
[1] 53456
#     PID TTY      STAT   TIME COMMAND
      1 pts/3    S+     0:00 sleep 999
      3 pts/3    S+     0:00 sleep 555
      5 pts/3    R+     0:00 ps a

# ps h -o 'comm' $!     # Show that background job is unshare(1)
unshare
# kill $!               # Kill unshare(1)
# pidof sleep

The pidof(1) command prints no output, because the sleep processes got killed. More precisely: when the sleep process that has PID 1 in the namespace (i.e., the namespace's init process) was killed, that caused every other process in the namespace to be killed too. Rip ๐Ÿ’€

By contrast, a similar series of commands where --kill-child is not used shows that when unshare terminates, the processes in the PID namespace are not killed:

# unshare --pid --fork --mount-proc -- \
       bash --norc -c '(sleep 555 &) && (ps a &) && sleep 999' &
[1] 53479
#     PID TTY      STAT   TIME COMMAND
      1 pts/3    S+     0:00 sleep 999
      3 pts/3    S+     0:00 sleep 555
      5 pts/3    R+     0:00 ps a

# kill $!
# pidof sleep
53482 53480

Next up: creating a time namespace where the boottime clock is set to a point several years in the past. Time travel, but make it Linux. ๐Ÿฆ‹

# uptime -p             # Show uptime in initial time namespace
up 21 hours, 30 minutes
# unshare --time --fork --boottime 300000000 uptime -p
up 9 years, 28 weeks, 1 day, 2 hours, 50 minutes

And finally, this one executes a chroot into the directory /chroot/powerpc/jessie and installs the interpreter /bin/qemu-ppc-static to execute the powerpc binaries:

$  unshare --map-root-user --fork --pid --load-interp=":qemu-ppc:M::\\x7fELF\\x01\\x02\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x00\\x14:\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\x00\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xfe\\xff\\xff:/bin/qemu-ppc-static:OCF" --root=/chroot/powerpc/jessie /bin/bash -l

The load-interp parameter can be read as following:

  • qemu-ppc โ€” is the name of the new file created below /proc/sys/fs/binfmt_misc to register the interpreter.
  • M โ€” defines the interpreter for a given type of magic number.
  • \\x7fELF\\x01\\x02\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x00\\x1 โ€” is the magic number to recognize the file to interpret (in this case, the ELF header for PPC32).
  • \\xff\\xff\\xff\\xff\\xff\\xff\\xff\\x00\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xfe\\xff\\xff โ€” the mask to apply to the magic number.
  • /bin/qemu-ppc-static โ€” the interpreter to use with the file.
  • OCF โ€” the file is open by the kernel with credential and security tokens of the file itself, and loaded as soon as we register it.

๐Ÿ‘‘ AUTHORS ๐Ÿ‘‘

Mikhail Gusarov <dottedmag@dottedmag.net>, Karel Zak <kzak@redhat.com>


๐Ÿฆ‹ SEE ALSO ๐Ÿฆ‹

newuidmap(1), newgidmap(1), nsenter(1), lsns(8), clone(2), unshare(2), namespaces(7), mount(8)


๐Ÿ’€ REPORTING BUGS ๐Ÿ’€

Found a bug? Bestie, please use the issue tracker: <https://github.com/util-linux/util-linux/issues>.

๐ŸŒˆ AVAILABILITY ๐ŸŒˆ

okay bestie, so if you're like "where do I even get this magical command," here's the tea ๐Ÿต โ€” unshare is part of the util-linux package, like the whole squad of essential Linux utilities. it's not out here living on its own, it comes with the friend group. ๐Ÿ‘‘

and you can grab the whole package from the Linux Kernel Archive, right here:

https://www.kernel.org/pub/linux/utils/util-linux/

that's the canonical source, no sketchy third-party vibes, no random mirror energy, just the real thing. โœจ


๐Ÿ’… so yeah โ€” go forth, download it, unshare all the things, and remember: this whole page lives in the util-linux 2.42.4 release, dated 2026-09-21. that's the version, that's the date, that's the lore. ๐ŸŽ€

and that's a wrap on UNSHARE(1), bestie โ€” go forth and namespace responsibly ๐Ÿฆ‹๐ŸŒธ๐Ÿ’–

๐Ÿ“ฆ where this page comes from
  • arch rolling: util-linux 2.42.4-1 ยท BSD-2-Clause AND BSD-3-Clause AND BSD-4-Clause-UC AND GPL-2.0-only AND GPL-2.0-or-later AND GPL-3.0-or-later AND ISC AND LGPL-2.1-or-later AND LicenseRef-PublicDomain
  • ๐Ÿ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms