0

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

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:

how to unshare network for current process

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.