I'd like to run a shell that behaves exactly like the parent but without network. Why do I have to su <login>
after unshare
?

- 1,237
1 Answers
I'm surprised you can still su user
, afaik after Linux kernel 3.19 the su
command can become confused.
The unshare command isn't flexible enough to do it: it allows only a mapping to root. You have to map to yourself, after unshare
, but before any fork/exec by writing "<user> <user> 1"
to /proc/self/uid_map
(and same for /proc/self/gid_map
). All recent kernels also require to write first deny
to /proc/$$/setgroups
: all supplementary groups (eg: video) will have to be lost, this is unavoidable, like with unshare -U/-r
.
Here's a very simple C program as proof of concept only, which doesn't do any checks to just do what you asked, but only if run by an user with uid/gid 1000/1000: lose network. Feel free to improve it.
#define _GNU_SOURCE
#include <sched.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
int fd;
unshare(CLONE_NEWUSER|CLONE_NEWNET);
fd=open("/proc/self/setgroups",O_WRONLY);
write(fd,"deny",4);
close(fd);
fd=open("/proc/self/uid_map",O_WRONLY);
write(fd,"1000 1000 1",11);
close(fd);
fd=open("/proc/self/gid_map",O_WRONLY);
write(fd,"1000 1000 1",11);
close(fd);
execvp(argv[1],argv+1);
}
If the file is called removenet.c
, compile it with gcc -o removenet removenet.c
.
$ id
uid=1000(user) gid=1000(user) groups=1000(user),44(video)
$ ip -br a
lo UNKNOWN 127.0.0.1/8 ::1/128
eth0@if11 UP 10.0.3.66/24 fe80::216:3eff:fe6a:c1e9/64
$ ./removenet bash
$ id
uid=1000(user) gid=1000(user) groups=1000(user),65534(nogroup)
$ ip -br a
lo DOWN
Note also that the new network namespace has its lo
interface starting down, and since you're not root, you can't even set it up.
You can run variants of this program to revert to your former user after becoming root with eg unshare -r -n -m
, by changing again into a new user namespace. This allows to set up some environment first, like mounting /sys
to not see the former interfaces there, bringing the lo
interface up, etc. See my answer to a similar question there (with the same code, you just have to add again |CLONE_NEWNET
):
unshare --map-root-user switch to original uid/username after setup
To be clear: I don't know of any standard utility that exists able to do what you're asking with a simple shell command. So you have to resort to use an other language than shell: C, python, ... there's even ctypes.sh foreign function interface for bash.
This other answer of mine gives also some additional informations and an other "language", the gdb debugger:

- 36,364
- 2
- 73
- 118
unshare
can do it:unshare -U --map-user=$(id -u) --map-group=$(id -g) -n
(the group part silently sets--setgroups=deny
which should not be given again else this would trigger an error). – A.B Oct 16 '21 at 10:42