diff options
Diffstat (limited to 'src/cmd/go/internal/load/pkg.go')
-rw-r--r-- | src/cmd/go/internal/load/pkg.go | 94 |
1 files changed, 78 insertions, 16 deletions
diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go index 60de666164..65b17012a3 100644 --- a/src/cmd/go/internal/load/pkg.go +++ b/src/cmd/go/internal/load/pkg.go @@ -18,6 +18,7 @@ import ( "sort" "strings" "unicode" + "unicode/utf8" "cmd/go/internal/base" "cmd/go/internal/buildid" @@ -53,6 +54,8 @@ type PackagePublic struct { BinaryOnly bool `json:",omitempty"` // package cannot be recompiled // Source files + // If you add to this list you MUST add to p.AllFiles (below) too. + // Otherwise file name security lists will not apply to any new additions. GoFiles []string `json:",omitempty"` // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles) CgoFiles []string `json:",omitempty"` // .go sources files that import "C" IgnoredGoFiles []string `json:",omitempty"` // .go sources ignored due to build constraints @@ -84,12 +87,38 @@ type PackagePublic struct { DepsErrors []*PackageError `json:",omitempty"` // errors loading dependencies // Test information + // If you add to this list you MUST add to p.AllFiles (below) too. + // Otherwise file name security lists will not apply to any new additions. TestGoFiles []string `json:",omitempty"` // _test.go files in package TestImports []string `json:",omitempty"` // imports from TestGoFiles XTestGoFiles []string `json:",omitempty"` // _test.go files outside package XTestImports []string `json:",omitempty"` // imports from XTestGoFiles } +// AllFiles returns the names of all the files considered for the package. +// This is used for sanity and security checks, so we include all files, +// even IgnoredGoFiles, because some subcommands consider them. +// The go/build package filtered others out (like foo_wrongGOARCH.s) +// and that's OK. +func (p *Package) AllFiles() []string { + return str.StringList( + p.GoFiles, + p.CgoFiles, + p.IgnoredGoFiles, + p.CFiles, + p.CXXFiles, + p.MFiles, + p.HFiles, + p.FFiles, + p.SFiles, + p.SwigFiles, + p.SwigCXXFiles, + p.SysoFiles, + p.TestGoFiles, + p.XTestGoFiles, + ) +} + type PackageInternal struct { // Unexported fields are not part of the public API. Build *build.Package @@ -1025,22 +1054,8 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) *Package // To avoid problems on case-insensitive files, we reject any package // where two different input files have equal names under a case-insensitive // comparison. - f1, f2 := str.FoldDup(str.StringList( - p.GoFiles, - p.CgoFiles, - p.IgnoredGoFiles, - p.CFiles, - p.CXXFiles, - p.MFiles, - p.HFiles, - p.FFiles, - p.SFiles, - p.SysoFiles, - p.SwigFiles, - p.SwigCXXFiles, - p.TestGoFiles, - p.XTestGoFiles, - )) + inputs := p.AllFiles() + f1, f2 := str.FoldDup(inputs) if f1 != "" { p.Error = &PackageError{ ImportStack: stk.Copy(), @@ -1049,6 +1064,37 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) *Package return p } + // If first letter of input file is ASCII, it must be alphanumeric. + // This avoids files turning into flags when invoking commands, + // and other problems we haven't thought of yet. + // Also, _cgo_ files must be generated by us, not supplied. + // They are allowed to have //go:cgo_ldflag directives. + // The directory scan ignores files beginning with _, + // so we shouldn't see any _cgo_ files anyway, but just be safe. + for _, file := range inputs { + if !SafeArg(file) || strings.HasPrefix(file, "_cgo_") { + p.Error = &PackageError{ + ImportStack: stk.Copy(), + Err: fmt.Sprintf("invalid input file name %q", file), + } + return p + } + } + if name := pathpkg.Base(p.ImportPath); !SafeArg(name) { + p.Error = &PackageError{ + ImportStack: stk.Copy(), + Err: fmt.Sprintf("invalid input directory name %q", name), + } + return p + } + if !SafeArg(p.ImportPath) { + p.Error = &PackageError{ + ImportStack: stk.Copy(), + Err: fmt.Sprintf("invalid import path %q", p.ImportPath), + } + return p + } + // Build list of imported packages and full dependency list. imports := make([]*Package, 0, len(p.Imports)) deps := make(map[string]*Package) @@ -1164,6 +1210,22 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) *Package return p } +// SafeArg reports whether arg is a "safe" command-line argument, +// meaning that when it appears in a command-line, it probably +// doesn't have some special meaning other than its own name. +// Obviously args beginning with - are not safe (they look like flags). +// Less obviously, args beginning with @ are not safe (they look like +// GNU binutils flagfile specifiers, sometimes called "response files"). +// To be conservative, we reject almost any arg beginning with non-alphanumeric ASCII. +// We accept leading . _ and / as likely in file system paths. +func SafeArg(name string) bool { + if name == "" { + return false + } + c := name[0] + return '0' <= c && c <= '9' || 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || c == '.' || c == '_' || c == '/' || c >= utf8.RuneSelf +} + // usesSwig reports whether the package needs to run SWIG. func (p *Package) UsesSwig() bool { return len(p.SwigFiles) > 0 || len(p.SwigCXXFiles) > 0 |