os/exec: use environment variables for user token when present

Builds upon the changes from #32000 which supported sourcing environment
variables for a new process from the environment of a Windows user token
when supplied.

But due to the logic of os/exec, the Env field of a process was
always non-nil when it reached that change.

This change moves the logic up to os/exec, specifically when
os.ProcAttr is being built for the os.StartProcess call, this
ensures that if a user token has been supplied and no Env slice has
been provided on the command it will be sourced from the user's
environment.

If no token is provided, or the program is compiled for any other
platform than Windows, the default environment will be sourced from
syscall.Environ().

Fixes #35314

Change-Id: I4c1722e90b91945eb6980d5c5928183269b50487
GitHub-Last-Rev: 32216b7291
GitHub-Pull-Request: golang/go#37402
Reviewed-on: https://go-review.googlesource.com/c/go/+/220587
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
Liam 'Auzzie' Haworth 2020-02-25 00:11:28 +00:00 committed by Ian Lance Taylor
parent 17f7c12eb9
commit e0c3ded337
6 changed files with 48 additions and 25 deletions

View File

@ -153,6 +153,7 @@ var pkgDeps = map[string][]string{
"internal/syscall/unix": {"L0", "syscall"},
"internal/syscall/windows": {"L0", "syscall", "internal/syscall/windows/sysdll", "unicode/utf16"},
"internal/syscall/windows/registry": {"L0", "syscall", "internal/syscall/windows/sysdll", "unicode/utf16"},
"internal/syscall/execenv": {"L0", "syscall", "internal/syscall/windows", "unicode/utf16"},
"time": {
// "L0" without the "io" package:
"errors",
@ -170,10 +171,10 @@ var pkgDeps = map[string][]string{
"internal/cfg": {"L0"},
"internal/poll": {"L0", "internal/oserror", "internal/race", "syscall", "time", "unicode/utf16", "unicode/utf8", "internal/syscall/windows", "internal/syscall/unix"},
"internal/testlog": {"L0"},
"os": {"L1", "os", "syscall", "time", "internal/oserror", "internal/poll", "internal/syscall/windows", "internal/syscall/unix", "internal/testlog"},
"os": {"L1", "os", "syscall", "time", "internal/oserror", "internal/poll", "internal/syscall/windows", "internal/syscall/unix", "internal/syscall/execenv", "internal/testlog"},
"path/filepath": {"L2", "os", "syscall", "internal/syscall/windows"},
"io/ioutil": {"L2", "os", "path/filepath", "time"},
"os/exec": {"L2", "os", "context", "path/filepath", "syscall"},
"os/exec": {"L2", "os", "context", "path/filepath", "syscall", "internal/syscall/execenv"},
"os/signal": {"L2", "os", "syscall"},
// OS enables basic operating system functionality,

View File

@ -0,0 +1,19 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !windows
package execenv
import "syscall"
// Default will return the default environment
// variables based on the process attributes
// provided.
//
// Defaults to syscall.Environ() on all platforms
// other than Windows.
func Default(sys *syscall.SysProcAttr) ([]string, error) {
return syscall.Environ(), nil
}

View File

@ -1,8 +1,10 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package os
// +build windows
package execenv
import (
"internal/syscall/windows"
@ -11,9 +13,17 @@ import (
"unsafe"
)
func environForSysProcAttr(sys *syscall.SysProcAttr) (env []string, err error) {
// Default will return the default environment
// variables based on the process attributes
// provided.
//
// If the process attributes contain a token, then
// the environment variables will be sourced from
// the defaults for that user token, otherwise they
// will be sourced from syscall.Environ().
func Default(sys *syscall.SysProcAttr) (env []string, err error) {
if sys == nil || sys.Token == 0 {
return Environ(), nil
return syscall.Environ(), nil
}
var block *uint16
err = windows.CreateEnvironmentBlock(&block, sys.Token, false)

View File

@ -1,13 +0,0 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !windows
package os
import "syscall"
func environForSysProcAttr(sys *syscall.SysProcAttr) ([]string, error) {
return Environ(), nil
}

View File

@ -24,6 +24,7 @@ import (
"bytes"
"context"
"errors"
"internal/syscall/execenv"
"io"
"os"
"path/filepath"
@ -222,11 +223,11 @@ func interfaceEqual(a, b interface{}) bool {
return a == b
}
func (c *Cmd) envv() []string {
func (c *Cmd) envv() ([]string, error) {
if c.Env != nil {
return c.Env
return c.Env, nil
}
return os.Environ()
return execenv.Default(c.SysProcAttr)
}
func (c *Cmd) argv() []string {
@ -413,11 +414,15 @@ func (c *Cmd) Start() error {
}
c.childFiles = append(c.childFiles, c.ExtraFiles...)
var err error
envv, err := c.envv()
if err != nil {
return err
}
c.Process, err = os.StartProcess(c.Path, c.argv(), &os.ProcAttr{
Dir: c.Dir,
Files: c.childFiles,
Env: addCriticalEnv(dedupEnv(c.envv())),
Env: addCriticalEnv(dedupEnv(envv)),
Sys: c.SysProcAttr,
})
if err != nil {

View File

@ -7,6 +7,7 @@
package os
import (
"internal/syscall/execenv"
"runtime"
"syscall"
)
@ -39,7 +40,7 @@ func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err e
Sys: attr.Sys,
}
if sysattr.Env == nil {
sysattr.Env, err = environForSysProcAttr(sysattr.Sys)
sysattr.Env, err = execenv.Default(sysattr.Sys)
if err != nil {
return nil, err
}