Skip to content

os/exec: $HOME not updated when running command as a different UID #33788

@wanrui

Description

@wanrui

What version of Go are you using (go version)?

$ go version
go version go1.12.5 linux/amd64

Does this issue reproduce with the latest release?

yes

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/wanrui/.cache/go-build"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/wanrui/workspace"
GOPROXY="https://goproxy.cn"
GORACE=""
GOROOT="/home/wanrui/go"
GOTMPDIR=""
GOTOOLDIR="/home/wanrui/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/dev/null"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build173649310=/tmp/go-build -gno-record-gcc-switches"

What did you do?

there is testfile asynccmd .go

package main

import (
        "bufio"
        "context"
        "flag"
        "fmt"
        _ "net/http/pprof"
        "os/exec"
        "os/user"
        _ "runtime/pprof"
        "strconv"
        "syscall"
        "time"
)

const omg = `ls -al /tmp/ && nohup sleep 1000 &`

func main() {
        timeout := flag.Int("timeout", 120, "")
        command := flag.String("cmd", omg, "")
        runUser := flag.String("user", "www", "")
        pgid := flag.Bool("pgid", true, "Setpgid 开关。")

        flag.Parse()

        ctx, cancle := context.WithTimeout(context.Background(), time.Second*time.Duration(*timeout))
        defer cancle()
        cmd := exec.CommandContext(ctx, "/bin/bash", "-c", *command)

        user, _ := user.Lookup(*runUser)
        uid, _ := strconv.Atoi(user.Uid)
        gid, _ := strconv.Atoi(user.Gid)
        sysProcAttr := &syscall.SysProcAttr{
                Setpgid: *pgid,
                Credential: &syscall.Credential{
                        Uid: uint32(uid),
                        Gid: uint32(gid),
                },
        }
        cmd.SysProcAttr = sysProcAttr

        stdout, _ := cmd.StdoutPipe()
        stderr, _ := cmd.StderrPipe()
        if err := cmd.Start(); err != nil {
                fmt.Println("cmd.start occur error", err)
                return
        }

        go func() {
                b := bufio.NewReader(stdout)
                for {
                        buf, err := b.ReadBytes('\n')
                        if err != nil {
                                fmt.Println("read stdout err:", string(buf), err)
                                return
                        }
                        fmt.Println("read stdout buff:", string(buf))
                }

        }()

        go func() {
                b := bufio.NewReader(stderr)
                for {
                        buf, err := b.ReadBytes('\n')
                        if err != nil {
                                fmt.Println("read stderr err:", string(buf), err)
                                return
                        }
                        fmt.Println("read stderr buff:", string(buf))
                }

        }()

        if err := cmd.Wait(); err != nil {
                syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL)
                fmt.Println("cmd.wait occur error ", err)
        }

}

there is file : /home/www/.bash_profile

# .bash_profile
# Get the aliases and functions
echo $HOME
if [ -f ~/.bashrc ]; then
        . ~/.bashrc
fi
export PATH

in /root dir run follow command:

./asynccmd -user="www" -cmd=" source /home/www/.bash_profile"

What did you expect to see?

read stdout buff: /home/www

read stdout buff: 

read stdout err: java: read |0: file already closed
read stderr err:  read |0: file already closed

What did you see instead?

out is:

read stdout buff: /root

read stdout buff: 

read stdout err: java: read |0: file already closed
read stderr err:  read |0: file already closed

Metadata

Metadata

Assignees

No one assigned

    Labels

    DocumentationIssues describing a change to documentation.NeedsInvestigationSomeone must examine and confirm this is a valid issue and not a duplicate of an existing one.

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions