4

I am experimenting with user namespaces using Go on Linux. The thing that I cannot figure out is that although am setting the uid and gid mappings when creating the namespace it still identifies as the nobody user when I launch the binary using sudo but when I launch it using the normal user everything works fine. For reference please see my code below

...
cmd := exec.Command("/bin/sh")
    cmd.Stdout = os.Stdout
    cmd.Stdin = os.Stdin
    cmd.Stderr = os.Stderr
    cmd.SysProcAttr = &syscall.SysProcAttr{
        Cloneflags: syscall.CLONE_NEWUSER,
        UidMappings: []syscall.SysProcIDMap{
            {
                ContainerID: 0,
                HostID:      1000,
                Size:        1,
            },
        },
        GidMappings: []syscall.SysProcIDMap{
            {
                ContainerID: 0,
                HostID:      1000,
                Size:        1,
            },
        },
    }
    cmd.Run()

....
...

From the host I can confirm that indeed the user and group mappings were successful. The current pid is 87751

sudo cat /proc/87751/uid_map
         0       1000          1
sudo cat /proc/87751/gid_map
         0       1000          1

But when I run the binary after building

go build -o user_n
sudo ./user_n
sh-5.0$ whoami 
nobody
sh-5.0$ id
uid=65534(nobody) gid=65534(nobody) groups=65534(nobody) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

But when I run the binary using the normal user it works as expected

./user_n
sh-5.0# whoami
root
sh-5.0# id
uid=0(root) gid=0(root) groups=0(root),65534(nobody) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

While running the binary using the normal user is an option I would like to know why running using sudo does not give the expected results. Any pointers will be greatly appreciated.

More info

Fedora 31
Kernel 5.3.11-100.fc29.x86_64
go version go1.14.3 linux/amd64
Rachid K.
  • 4,490
  • 3
  • 11
  • 30
  • 1
    In the first case, you are running as root user (sudo) for which there is no mapping in the child user namespace. Hence, the "nobody" id. In the second case, you run the program as id 1000 for which the mapping says : 1000 becomes root in the child user namespace. – Rachid K. Oct 18 '20 at 14:49
  • @RachidK.: Is that okay to post as an answer? It looks complete enough to me. – Ry- Oct 19 '20 at 06:18
  • @Ry-: I am OK. Am I supposed to make it ? (I am only 1 week old in StackOverflow, I don't know all the rules) – Rachid K. Oct 19 '20 at 08:19
  • @RachidK.: You don’t have to, but I don’t see why not! I’d vote for it. :) – Ry- Oct 19 '20 at 08:39

1 Answers1

2

In the first case, you are running as root user (through sudo) for which there is no mapping specified in the child user namespace. Hence, the resulting "nobody" id.

In the second case, you run the program as user id 1000 for which the mapping says : 1000 becomes root in the child user namespace. Hence, the resulting "root" id.

Rachid K.
  • 4,490
  • 3
  • 11
  • 30
  • Thanks . So does this mean that a process cannot make mappings to any arbitrary user id that exists on the host. i.e the process doing the mapping can only map to the user id that owns it ? @Rachid K – Michael Mwangi Oct 19 '20 at 11:45
  • 1
    A user can map himself into any user in a child namespace. To add other mappings, you need to use so-called setuid helpers like newuidmap and newgidmap. – Rachid K. Oct 19 '20 at 11:59
  • 1
    @MichaelMwangi: That’s not what it means. You added an entry for `HostID: 1000`, which isn’t your UID when running with sudo (i.e. as root). Add another entry for `HostID: 0`, or (probably better) drop privileges back to 1000 before running the command. – Ry- Oct 19 '20 at 12:00
  • Thank you for the suggestions. Let me look at it again from that angle @RachidK. – Michael Mwangi Oct 20 '20 at 05:59