src/cmd/compile/internal/gc/noder.go | 28 +++++++++++++++++++++++++++- src/cmd/go/internal/load/pkg.go | 1 + diff --git a/src/cmd/compile/internal/gc/noder.go b/src/cmd/compile/internal/gc/noder.go index fff04bcbefb7f534897c61af10039adc2d7fd4e9..6f32e52ec80917bd02182988afd55e0267a0f3f9 100644 --- a/src/cmd/compile/internal/gc/noder.go +++ b/src/cmd/compile/internal/gc/noder.go @@ -1346,8 +1346,22 @@ break } p.linknames = append(p.linknames, linkname{pos, f[1], f[2]}) + case strings.HasPrefix(text, "go:cgo_import_dynamic "): + // This is permitted for general use because Solaris + // code relies on it in golang.org/x/sys/unix and others. + fields := pragmaFields(text) + if len(fields) >= 4 { + lib := strings.Trim(fields[3], `"`) + if lib != "" && !safeArg(lib) && !isCgoGeneratedFile(pos) { + p.error(syntax.Error{Pos: pos, Msg: fmt.Sprintf("invalid library name %q in cgo_import_dynamic directive", lib)}) + } + p.pragcgobuf += p.pragcgo(pos, text) + return pragmaValue("go:cgo_import_dynamic") + } + fallthrough case strings.HasPrefix(text, "go:cgo_"): - // For security, we disallow //go:cgo_* directives outside cgo-generated files. + // For security, we disallow //go:cgo_* directives other + // than cgo_import_dynamic outside cgo-generated files. // Exception: they are allowed in the standard library, for runtime and syscall. if !isCgoGeneratedFile(pos) && !compiling_std { p.error(syntax.Error{Pos: pos, Msg: fmt.Sprintf("//%s only allowed in cgo-generated code", text)}) @@ -1381,6 +1395,18 @@ // (primarily misuse of linker flags), other files are not. // See golang.org/issue/23672. func isCgoGeneratedFile(pos src.Pos) bool { return strings.HasPrefix(filepath.Base(filepath.Clean(pos.AbsFilename())), "_cgo_") +} + +// 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. +// This is copied from SafeArg in cmd/go/internal/load/pkg.go. +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 } func mkname(sym *types.Sym) *Node { diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go index bbd75bc9b6774d9fd467922140f78e22bb7b89fb..b006d4137c61282cf4c9cd9bdc8c6e66457c6392 100644 --- a/src/cmd/go/internal/load/pkg.go +++ b/src/cmd/go/internal/load/pkg.go @@ -1206,6 +1206,7 @@ // 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. +// There is a copy of this function in cmd/compile/internal/gc/noder.go. func SafeArg(name string) bool { if name == "" { return false