Search code examples
linuxgoexec

setuid when using exec.Cmd.Start()


Is it possible to configure a Cmd to set the UID+GID of a process started with exec.Cmd.Start()? I'm looking for behavior similar to libuv_spawn where I can set UV_PROCESS_SET{UID,GID} and pass those in as options.

I initially thought I could use UidMapping and GidMapping in SysProcAttr but that seems to be associated with namespaces.

Is there a way that doesn't involve me calling fork/exec/setuid by hand?

Working Code

(Thanks to @Dave and @JimB) The Credential field of SysProcAttr is where the magic can happen.

    cmd := exec.CommandContext(context.Background(), "whoami")
    cmd.Stdout = os.Stdout
    cmd.Stderr = os.Stderr
    cmd.SysProcAttr = &syscall.SysProcAttr{
        Credential: &syscall.Credential{
            Uid: uint32(myUID),
            Gid: uint32(myGID),
        },
    }
    if err := cmd.Start(); err != nil {
        panic(err)
    }
    if err := cmd.Wait(); err != nil {
        panic(err)
    }

Which spits out the appropriate username!


Solution

  • You'd need to use os.StartProcess:

    attr := &os.ProcAttr{
        Files: []*os.File{os.Stdin, os.Stdout, os.Stderr},
        Sys: &syscall.SysProcAttr{
            Credential: &syscall.Credential{
                Uid: uint32(uid),
                Gid: uint32(gid),   
            },
        },
    }
    args := []string{
        "/usr/bin/whoami",
    }
    process, err := os.StartProcess(args[0], args, attr)