]> Cypherpunks repositories - gostls13.git/commitdiff
[release-branch.go1.14-security] all: introduce and use internal/execabs
authorRoland Shoemaker <roland@golang.org>
Fri, 15 Jan 2021 20:14:06 +0000 (12:14 -0800)
committerRoland Shoemaker <roland@golang.org>
Sat, 16 Jan 2021 01:44:08 +0000 (17:44 -0800)
Introduces a wrapper around os/exec, internal/execabs, for use in
all commands. This wrapper prevents exec.LookPath and exec.Command from
running executables in the current directory.

All imports of os/exec in non-test files in cmd/ are replaced with
imports of internal/execabs.

This issue was reported by RyotaK.

Fixes CVE-2021-3115

Change-Id: I0423451a6e27ec1e1d6f3fe929ab1ef69145c08f
Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/955304
Reviewed-by: Russ Cox <rsc@google.com>
Reviewed-by: Katie Hockman <katiehockman@google.com>
(cherry picked from commit 44f09a6990ccf4db601cbf8208c89ac4e888f884)
Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/955309

36 files changed:
src/cmd/api/goapi.go
src/cmd/api/run.go
src/cmd/cgo/out.go
src/cmd/cgo/util.go
src/cmd/compile/internal/ssa/html.go
src/cmd/cover/func.go
src/cmd/cover/testdata/toolexec.go
src/cmd/dist/buildtool.go
src/cmd/doc/dirs.go
src/cmd/fix/typecheck.go
src/cmd/go/internal/base/base.go
src/cmd/go/internal/bug/bug.go
src/cmd/go/internal/generate/generate.go
src/cmd/go/internal/modfetch/codehost/codehost.go
src/cmd/go/internal/modfetch/codehost/git.go
src/cmd/go/internal/test/test.go
src/cmd/go/internal/tool/tool.go
src/cmd/go/internal/vet/vetflag.go
src/cmd/go/internal/work/build.go
src/cmd/go/internal/work/buildid.go
src/cmd/go/internal/work/exec.go
src/cmd/go/internal/work/gccgo.go
src/cmd/go/testdata/addmod.go
src/cmd/internal/browser/browser.go
src/cmd/internal/diff/diff.go
src/cmd/internal/dwarf/dwarf.go
src/cmd/link/internal/ld/execarchive.go
src/cmd/link/internal/ld/lib.go
src/cmd/test2json/main.go
src/cmd/trace/pprof.go
src/go/build/build.go
src/go/build/deps_test.go
src/go/internal/gccgoimporter/gccgoinstallation.go
src/internal/execabs/execabs.go [new file with mode: 0644]
src/internal/execabs/execabs_test.go [new file with mode: 0644]
src/internal/goroot/gc.go

index b46b3102678b92be6d2f4ec52fcf8dc416496871..26eb32866e6b53a826bb53910915b1b3e34030c0 100644 (file)
@@ -16,11 +16,11 @@ import (
        "go/parser"
        "go/token"
        "go/types"
+       exec "internal/execabs"
        "io"
        "io/ioutil"
        "log"
        "os"
-       "os/exec"
        "path/filepath"
        "regexp"
        "runtime"
index a36f1179c16e9839fa7f1bd417b788a27d9df6db..ecb1d0f81aa46695d47634b94eb6571368e0ffef 100644 (file)
@@ -10,9 +10,9 @@ package main
 
 import (
        "fmt"
+       exec "internal/execabs"
        "log"
        "os"
-       "os/exec"
        "path/filepath"
        "runtime"
        "strings"
index d447bcb5436e13c9df77ee73de8513fdd8c16bb5..698181ce1b620ccbcfdec1c13b565e9dead94168 100644 (file)
@@ -13,11 +13,11 @@ import (
        "go/ast"
        "go/printer"
        "go/token"
+       exec "internal/execabs"
        "internal/xcoff"
        "io"
        "io/ioutil"
        "os"
-       "os/exec"
        "path/filepath"
        "regexp"
        "sort"
index 779f7be2259b3750166b6edce318adb779e7a3a6..00d931b98a0c1e8416d5bb14334946dbd9a56304 100644 (file)
@@ -8,9 +8,9 @@ import (
        "bytes"
        "fmt"
        "go/token"
+       exec "internal/execabs"
        "io/ioutil"
        "os"
-       "os/exec"
 )
 
 // run runs the command argv, feeding in stdin on standard input.
index 1e76a673efbb2a1b7b8f47c2851b09e27c2984eb..068c3827258616fefbf3fc408e5cdfaa1fd2540f 100644 (file)
@@ -9,9 +9,9 @@ import (
        "cmd/internal/src"
        "fmt"
        "html"
+       exec "internal/execabs"
        "io"
        "os"
-       "os/exec"
        "path/filepath"
        "strconv"
        "strings"
index 988c4caebffe13dc11e6bffb304016abc5673723..ce7c771ac961971af670b00c1c79ea1c8b22153c 100644 (file)
@@ -15,9 +15,9 @@ import (
        "go/ast"
        "go/parser"
        "go/token"
+       exec "internal/execabs"
        "io"
        "os"
-       "os/exec"
        "path"
        "path/filepath"
        "runtime"
index 1769efedbeb678674045a9d6b9bbc08fb4e5ed30..386de79038a355c2de01fead816a1410479490f8 100644 (file)
@@ -16,7 +16,7 @@ package main
 
 import (
        "os"
-       "os/exec"
+       exec "internal/execabs"
        "strings"
 )
 
index a07e64b472b38762026acc82ee41a5ba654b254d..095ebbd0762fa337a50305bc47a1607a403daf6e 100644 (file)
@@ -298,8 +298,10 @@ func bootstrapFixImports(srcFile string) string {
                        continue
                }
                if strings.HasPrefix(line, `import "`) || strings.HasPrefix(line, `import . "`) ||
-                       inBlock && (strings.HasPrefix(line, "\t\"") || strings.HasPrefix(line, "\t. \"")) {
+                       inBlock && (strings.HasPrefix(line, "\t\"") || strings.HasPrefix(line, "\t. \"") || strings.HasPrefix(line, "\texec \"")) {
                        line = strings.Replace(line, `"cmd/`, `"bootstrap/cmd/`, -1)
+                       // During bootstrap, must use plain os/exec.
+                       line = strings.Replace(line, `exec "internal/execabs"`, `"os/exec"`, -1)
                        for _, dir := range bootstrapDirs {
                                if strings.HasPrefix(dir, "cmd/") {
                                        continue
index 38cbe7fa021973943c459461684f14b58220b7be..661624cfe4c168c793d582203de163f3169634e6 100644 (file)
@@ -7,9 +7,9 @@ package main
 import (
        "bytes"
        "fmt"
+       exec "internal/execabs"
        "log"
        "os"
-       "os/exec"
        "path/filepath"
        "regexp"
        "strings"
index 66e0cdcec056dfccf0d376c657345ed6626010be..8390e4446c030dbfe1d52d2a47832684f0b6c4be 100644 (file)
@@ -9,9 +9,9 @@ import (
        "go/ast"
        "go/parser"
        "go/token"
+       exec "internal/execabs"
        "io/ioutil"
        "os"
-       "os/exec"
        "path/filepath"
        "reflect"
        "runtime"
index 272da55681258dff961bb67a6f1c13dbf36ba1e5..15e603552cfc234dce45b2216f1c74fd86ef7d1e 100644 (file)
@@ -12,9 +12,9 @@ import (
        "flag"
        "fmt"
        "go/scanner"
+       exec "internal/execabs"
        "log"
        "os"
-       "os/exec"
        "strings"
        "sync"
 
index fe71281ef054ebebf4a3f51c0f267acbdc4aa999..9434bc2b1c11b23967b1b3642b367eb02fda4ba7 100644 (file)
@@ -8,11 +8,11 @@ package bug
 import (
        "bytes"
        "fmt"
+       exec "internal/execabs"
        "io"
        "io/ioutil"
        urlpkg "net/url"
        "os"
-       "os/exec"
        "path/filepath"
        "regexp"
        "runtime"
index 315db69de8a56b2fb522a39dfd408a61009192f4..758fa3be582656a07bb3679764bc1dcb2a26870e 100644 (file)
@@ -9,10 +9,10 @@ import (
        "bufio"
        "bytes"
        "fmt"
+       exec "internal/execabs"
        "io"
        "log"
        "os"
-       "os/exec"
        "path/filepath"
        "regexp"
        "strconv"
index 5867288c9669cf1ac22d8d8ef36dfa6ec051e6a6..383981da3438c1c11665205f2fdbceca279b8e37 100644 (file)
@@ -10,10 +10,10 @@ import (
        "bytes"
        "crypto/sha256"
        "fmt"
+       exec "internal/execabs"
        "io"
        "io/ioutil"
        "os"
-       "os/exec"
        "path/filepath"
        "strings"
        "sync"
index f08df512f02539bcadfce7b112c99bfef33e6f9f..aa696ecf8b5ac67121f4493004ba9ccca980d8db 100644 (file)
@@ -8,11 +8,11 @@ import (
        "bytes"
        "errors"
        "fmt"
+       exec "internal/execabs"
        "io"
        "io/ioutil"
        "net/url"
        "os"
-       "os/exec"
        "path/filepath"
        "sort"
        "strconv"
index 4ad142ccd874886d2acf0cc0272164f408dfa789..a23a1bbf2aebf266573344f731d2d987d6cb7b1f 100644 (file)
@@ -10,10 +10,10 @@ import (
        "errors"
        "fmt"
        "go/build"
+       exec "internal/execabs"
        "io"
        "io/ioutil"
        "os"
-       "os/exec"
        "path"
        "path/filepath"
        "regexp"
index 930eecb63f1c4955c842e6e7d10a936e77783254..f06c9038a063eaf0135552a9de1428b8941aedc9 100644 (file)
@@ -7,8 +7,8 @@ package tool
 
 import (
        "fmt"
+       exec "internal/execabs"
        "os"
-       "os/exec"
        "sort"
        "strings"
 
index e3de48bbffaa4b4be2252b1d95ab197d2a10db94..052b8f1bb0f0778afe08efa2eedd62ff4659e455 100644 (file)
@@ -9,9 +9,9 @@ import (
        "encoding/json"
        "flag"
        "fmt"
+       exec "internal/execabs"
        "log"
        "os"
-       "os/exec"
        "path/filepath"
        "strings"
 
index e3b25c937c345df292676d5ddde5fc0fea172477..c19e6f1a4379e647fe2801abe6d610c1b357d5f5 100644 (file)
@@ -8,8 +8,8 @@ import (
        "errors"
        "fmt"
        "go/build"
+       exec "internal/execabs"
        "os"
-       "os/exec"
        "path/filepath"
        "runtime"
        "strings"
index 7558a3091aa6c7a6646652b78dcc36a39951023b..5fbdbb6a37501d66e94d460c075f8d78995ecdec 100644 (file)
@@ -7,9 +7,9 @@ package work
 import (
        "bytes"
        "fmt"
+       exec "internal/execabs"
        "io/ioutil"
        "os"
-       "os/exec"
        "strings"
 
        "cmd/go/internal/base"
index b65e2a08793bb68b8888bdb3f0539775f64ed60c..d5c75062470effa6cef5e27199e3ba60ead7aa5a 100644 (file)
@@ -16,13 +16,13 @@ import (
        "encoding/json"
        "errors"
        "fmt"
+       exec "internal/execabs"
        "internal/lazyregexp"
        "io"
        "io/ioutil"
        "log"
        "math/rand"
        "os"
-       "os/exec"
        "path/filepath"
        "regexp"
        "runtime"
index 4c1f36dbd6a6807fcb2bed818470891dd5aa5d69..2f5d5d628374af53ec3cf70ffbea09906ee2be30 100644 (file)
@@ -6,9 +6,9 @@ package work
 
 import (
        "fmt"
+       exec "internal/execabs"
        "io/ioutil"
        "os"
-       "os/exec"
        "path/filepath"
        "strings"
 
index d9c3aab9c49630306a61607398f21b451283b39c..9c74cf500b6e1954c0705ff751251f32a3e54786 100644 (file)
@@ -25,7 +25,7 @@ import (
        "io/ioutil"
        "log"
        "os"
-       "os/exec"
+       exec "internal/execabs"
        "path/filepath"
        "strings"
 
index 6867c85d2320406bb4c80b8960f5b958c6a2f196..577d31789f19afcb768e847cd69d2714e4d48b06 100644 (file)
@@ -6,8 +6,8 @@
 package browser
 
 import (
+       exec "internal/execabs"
        "os"
-       "os/exec"
        "runtime"
        "time"
 )
index e9d2c237800a9c6c658eb41db1b58dcff102fe18..c0ca2f310630cd7266a770d6b42748ae034cb050 100644 (file)
@@ -7,9 +7,9 @@
 package diff
 
 import (
+       exec "internal/execabs"
        "io/ioutil"
        "os"
-       "os/exec"
        "runtime"
 )
 
index 56b44a1ab5acac19b2d0c14d6caa1e70f72dac0a..f97a1279fef8b4730cbbf73b5b4329bbc9df65c0 100644 (file)
@@ -12,7 +12,7 @@ import (
        "cmd/internal/objabi"
        "errors"
        "fmt"
-       "os/exec"
+       exec "internal/execabs"
        "sort"
        "strconv"
        "strings"
index fe5cc4086573b4b7754ec604f6e64c09e6a7b3e2..4687c624de464611e7de9036ae187c3e94be6023 100644 (file)
@@ -7,8 +7,8 @@
 package ld
 
 import (
+       exec "internal/execabs"
        "os"
-       "os/exec"
        "path/filepath"
        "syscall"
 )
index cd63963d7fe771e9458a13f39bd4b183eefddb1b..be6ffa02243ce2aff1916edc286098d2ad0851d5 100644 (file)
@@ -51,11 +51,11 @@ import (
        "encoding/binary"
        "encoding/hex"
        "fmt"
+       exec "internal/execabs"
        "io"
        "io/ioutil"
        "log"
        "os"
-       "os/exec"
        "path/filepath"
        "runtime"
        "sort"
index 0385d8f246c358a39185e3c8642c07ff2aa16184..52bad6bec85895ddb8cf63f6bbeab508ca36acbc 100644 (file)
@@ -82,9 +82,9 @@ package main
 import (
        "flag"
        "fmt"
+       exec "internal/execabs"
        "io"
        "os"
-       "os/exec"
 
        "cmd/internal/test2json"
 )
index a31d71b013c5da41f935e902376c150444c6cbc4..e6ea1a4ab61531809db065c87800918da92f0bbe 100644 (file)
@@ -9,12 +9,12 @@ package main
 import (
        "bufio"
        "fmt"
+       exec "internal/execabs"
        "internal/trace"
        "io"
        "io/ioutil"
        "net/http"
        "os"
-       "os/exec"
        "path/filepath"
        "runtime"
        "sort"
index 1a122c615fe843a606ec4a88fff154ec98fd010b..9136319ad9e6eb7fcb48ea1164565ceab8bd16df 100644 (file)
@@ -12,13 +12,13 @@ import (
        "go/doc"
        "go/parser"
        "go/token"
+       exec "internal/execabs"
        "internal/goroot"
        "internal/goversion"
        "io"
        "io/ioutil"
        "log"
        "os"
-       "os/exec"
        pathpkg "path"
        "path/filepath"
        "runtime"
index 8eed6260a2b4438308ec75f696c1112f424b027e..6106afaa0cabc69210b2d33d6bf0325892571dc5 100644 (file)
@@ -207,6 +207,8 @@ var pkgDeps = map[string][]string{
        "internal/lazyregexp":      {"L2", "OS", "regexp"},
        "internal/lazytemplate":    {"L2", "OS", "text/template"},
 
+       "internal/execabs": {"L2", "OS", "fmt", "context", "reflect"},
+
        // L4 is defined as L3+fmt+log+time, because in general once
        // you're using L3 packages, use of fmt, log, or time is not a big deal.
        "L4": {
@@ -240,7 +242,7 @@ var pkgDeps = map[string][]string{
        "go/constant":               {"L4", "go/token", "math/big"},
        "go/importer":               {"L4", "go/build", "go/internal/gccgoimporter", "go/internal/gcimporter", "go/internal/srcimporter", "go/token", "go/types"},
        "go/internal/gcimporter":    {"L4", "OS", "go/build", "go/constant", "go/token", "go/types", "text/scanner"},
-       "go/internal/gccgoimporter": {"L4", "OS", "debug/elf", "go/constant", "go/token", "go/types", "internal/xcoff", "text/scanner"},
+       "go/internal/gccgoimporter": {"L4", "OS", "debug/elf", "go/constant", "go/token", "go/types", "internal/xcoff", "text/scanner", "internal/execabs"},
        "go/internal/srcimporter":   {"L4", "OS", "fmt", "go/ast", "go/build", "go/parser", "go/token", "go/types", "path/filepath"},
        "go/types":                  {"L4", "GOPARSER", "container/heap", "go/constant"},
 
@@ -272,7 +274,7 @@ var pkgDeps = map[string][]string{
        "encoding/pem":                   {"L4"},
        "encoding/xml":                   {"L4", "encoding"},
        "flag":                           {"L4", "OS"},
-       "go/build":                       {"L4", "OS", "GOPARSER", "internal/goroot", "internal/goversion"},
+       "go/build":                       {"L4", "OS", "GOPARSER", "internal/goroot", "internal/goversion", "internal/execabs"},
        "html":                           {"L4"},
        "image/draw":                     {"L4", "image/internal/imageutil"},
        "image/gif":                      {"L4", "compress/lzw", "image/color/palette", "image/draw"},
@@ -280,7 +282,7 @@ var pkgDeps = map[string][]string{
        "image/jpeg":                     {"L4", "image/internal/imageutil"},
        "image/png":                      {"L4", "compress/zlib"},
        "index/suffixarray":              {"L4", "regexp"},
-       "internal/goroot":                {"L4", "OS"},
+       "internal/goroot":                {"L4", "OS", "internal/execabs"},
        "internal/singleflight":          {"sync"},
        "internal/trace":                 {"L4", "OS", "container/heap"},
        "internal/xcoff":                 {"L4", "OS", "debug/dwarf"},
index 8fc7ce3232190c93bb74f445bf55be1929e4c786..e90a3cc0b0a343e601bc2fe6389e43a160c713b9 100644 (file)
@@ -7,8 +7,8 @@ package gccgoimporter
 import (
        "bufio"
        "go/types"
+       exec "internal/execabs"
        "os"
-       "os/exec"
        "path/filepath"
        "strings"
 )
diff --git a/src/internal/execabs/execabs.go b/src/internal/execabs/execabs.go
new file mode 100644 (file)
index 0000000..547c3a5
--- /dev/null
@@ -0,0 +1,70 @@
+// 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 execabs is a drop-in replacement for os/exec
+// that requires PATH lookups to find absolute paths.
+// That is, execabs.Command("cmd") runs the same PATH lookup
+// as exec.Command("cmd"), but if the result is a path
+// which is relative, the Run and Start methods will report
+// an error instead of running the executable.
+package execabs
+
+import (
+       "context"
+       "fmt"
+       "os/exec"
+       "path/filepath"
+       "reflect"
+       "unsafe"
+)
+
+var ErrNotFound = exec.ErrNotFound
+
+type (
+       Cmd       = exec.Cmd
+       Error     = exec.Error
+       ExitError = exec.ExitError
+)
+
+func relError(file, path string) error {
+       return fmt.Errorf("%s resolves to executable in current directory (.%c%s)", file, filepath.Separator, path)
+}
+
+func LookPath(file string) (string, error) {
+       path, err := exec.LookPath(file)
+       if err != nil {
+               return "", err
+       }
+       if filepath.Base(file) == file && !filepath.IsAbs(path) {
+               return "", relError(file, path)
+       }
+       return path, nil
+}
+
+func fixCmd(name string, cmd *exec.Cmd) {
+       if filepath.Base(name) == name && !filepath.IsAbs(cmd.Path) {
+               // exec.Command was called with a bare binary name and
+               // exec.LookPath returned a path which is not absolute.
+               // Set cmd.lookPathErr and clear cmd.Path so that it
+               // cannot be run.
+               lookPathErr := (*error)(unsafe.Pointer(reflect.ValueOf(cmd).Elem().FieldByName("lookPathErr").Addr().Pointer()))
+               if *lookPathErr == nil {
+                       *lookPathErr = relError(name, cmd.Path)
+               }
+               cmd.Path = ""
+       }
+}
+
+func CommandContext(ctx context.Context, name string, arg ...string) *exec.Cmd {
+       cmd := exec.CommandContext(ctx, name, arg...)
+       fixCmd(name, cmd)
+       return cmd
+
+}
+
+func Command(name string, arg ...string) *exec.Cmd {
+       cmd := exec.Command(name, arg...)
+       fixCmd(name, cmd)
+       return cmd
+}
diff --git a/src/internal/execabs/execabs_test.go b/src/internal/execabs/execabs_test.go
new file mode 100644 (file)
index 0000000..a0b88dd
--- /dev/null
@@ -0,0 +1,107 @@
+// 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 execabs
+
+import (
+       "context"
+       "fmt"
+       "io/ioutil"
+       "os"
+       "os/exec"
+       "path/filepath"
+       "runtime"
+       "testing"
+)
+
+func TestFixCmd(t *testing.T) {
+       cmd := &exec.Cmd{Path: "hello"}
+       fixCmd("hello", cmd)
+       if cmd.Path != "" {
+               t.Errorf("fixCmd didn't clear cmd.Path")
+       }
+       expectedErr := fmt.Sprintf("hello resolves to executable in current directory (.%chello)", filepath.Separator)
+       if err := cmd.Run(); err == nil {
+               t.Fatal("Command.Run didn't fail")
+       } else if err.Error() != expectedErr {
+               t.Fatalf("Command.Run returned unexpected error: want %q, got %q", expectedErr, err.Error())
+       }
+}
+
+func TestCommand(t *testing.T) {
+       for _, cmd := range []func(string) *Cmd{
+               func(s string) *Cmd { return Command(s) },
+               func(s string) *Cmd { return CommandContext(context.Background(), s) },
+       } {
+               tmpDir, err := ioutil.TempDir("", "execabs-test")
+               if err != nil {
+                       t.Fatalf("ioutil.TempDir failed: %s", err)
+               }
+               defer os.RemoveAll(tmpDir)
+               executable := "execabs-test"
+               if runtime.GOOS == "windows" {
+                       executable += ".exe"
+               }
+               if err = ioutil.WriteFile(filepath.Join(tmpDir, executable), []byte{1, 2, 3}, 0111); err != nil {
+                       t.Fatalf("ioutil.WriteFile failed: %s", err)
+               }
+               cwd, err := os.Getwd()
+               if err != nil {
+                       t.Fatalf("os.Getwd failed: %s", err)
+               }
+               defer os.Chdir(cwd)
+               if err = os.Chdir(tmpDir); err != nil {
+                       t.Fatalf("os.Chdir failed: %s", err)
+               }
+               if runtime.GOOS != "windows" {
+                       // add "." to PATH so that exec.LookPath looks in the current directory on
+                       // non-windows platforms as well
+                       origPath := os.Getenv("PATH")
+                       defer os.Setenv("PATH", origPath)
+                       os.Setenv("PATH", fmt.Sprintf(".:%s", origPath))
+               }
+               expectedErr := fmt.Sprintf("execabs-test resolves to executable in current directory (.%c%s)", filepath.Separator, executable)
+               if err = cmd("execabs-test").Run(); err == nil {
+                       t.Fatalf("Command.Run didn't fail when exec.LookPath returned a relative path")
+               } else if err.Error() != expectedErr {
+                       t.Errorf("Command.Run returned unexpected error: want %q, got %q", expectedErr, err.Error())
+               }
+       }
+}
+
+func TestLookPath(t *testing.T) {
+       tmpDir, err := ioutil.TempDir("", "execabs-test")
+       if err != nil {
+               t.Fatalf("ioutil.TempDir failed: %s", err)
+       }
+       defer os.RemoveAll(tmpDir)
+       executable := "execabs-test"
+       if runtime.GOOS == "windows" {
+               executable += ".exe"
+       }
+       if err = ioutil.WriteFile(filepath.Join(tmpDir, executable), []byte{1, 2, 3}, 0111); err != nil {
+               t.Fatalf("ioutil.WriteFile failed: %s", err)
+       }
+       cwd, err := os.Getwd()
+       if err != nil {
+               t.Fatalf("os.Getwd failed: %s", err)
+       }
+       defer os.Chdir(cwd)
+       if err = os.Chdir(tmpDir); err != nil {
+               t.Fatalf("os.Chdir failed: %s", err)
+       }
+       if runtime.GOOS != "windows" {
+               // add "." to PATH so that exec.LookPath looks in the current directory on
+               // non-windows platforms as well
+               origPath := os.Getenv("PATH")
+               defer os.Setenv("PATH", origPath)
+               os.Setenv("PATH", fmt.Sprintf(".:%s", origPath))
+       }
+       expectedErr := fmt.Sprintf("execabs-test resolves to executable in current directory (.%c%s)", filepath.Separator, executable)
+       if _, err := LookPath("execabs-test"); err == nil {
+               t.Fatalf("LookPath didn't fail when finding a non-relative path")
+       } else if err.Error() != expectedErr {
+               t.Errorf("LookPath returned unexpected error: want %q, got %q", expectedErr, err.Error())
+       }
+}
index 0f541d734b0418e54ffcf9200180a4969bb42c7d..ce72bc389656a43681504ee97feff50b60526f1a 100644 (file)
@@ -7,8 +7,8 @@
 package goroot
 
 import (
+       exec "internal/execabs"
        "os"
-       "os/exec"
        "path/filepath"
        "strings"
        "sync"