From 0006a3e9da633ca01122dcdb66995e2ca56305dd Mon Sep 17 00:00:00 2001 From: Archana Ravindar Date: Wed, 31 Jan 2024 13:48:15 +0530 Subject: [PATCH] Backport of fix https://go-review.googlesource.com/c/go/+/533215 to Go1.17 (CVE 2023-39323) --- misc/cgo/errors/errors_test.go | 1 + misc/cgo/errors/testdata/err5.go | 7 ++++++ src/cmd/compile/internal/noder/noder.go | 27 ++++++++++++++++++++++- src/cmd/compile/internal/syntax/parser.go | 4 +++- src/cmd/compile/internal/syntax/pos.go | 25 ++++++++++++++++----- 5 files changed, 57 insertions(+), 7 deletions(-) create mode 100644 misc/cgo/errors/testdata/err5.go diff --git a/misc/cgo/errors/errors_test.go b/misc/cgo/errors/errors_test.go index 68a30a44fe4..567f1478acf 100644 --- a/misc/cgo/errors/errors_test.go +++ b/misc/cgo/errors/errors_test.go @@ -107,6 +107,7 @@ func TestReportsTypeErrors(t *testing.T) { for _, file := range []string{ "err1.go", "err2.go", + "err5.go", "issue11097a.go", "issue11097b.go", "issue18452.go", diff --git a/misc/cgo/errors/testdata/err5.go b/misc/cgo/errors/testdata/err5.go new file mode 100644 index 00000000000..573ebe34da7 --- /dev/null +++ b/misc/cgo/errors/testdata/err5.go @@ -0,0 +1,7 @@ +// Copyright 2023 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 main +//line /tmp/_cgo_.go:1 +//go:cgo_dynamic_linker "/elf/interp" // ERROR HERE: only allowed in cgo-generated code +func main() {} diff --git a/src/cmd/compile/internal/noder/noder.go b/src/cmd/compile/internal/noder/noder.go index 5fcad096c28..03aaea629e3 100644 --- a/src/cmd/compile/internal/noder/noder.go +++ b/src/cmd/compile/internal/noder/noder.go @@ -172,6 +172,25 @@ func (p *noder) errorAt(pos syntax.Pos, format string, args ...interface{}) { base.ErrorfAt(p.makeXPos(pos), format, args...) } +// trimFilename returns the "trimmed" filename of b, which is the +// absolute filename after applying -trimpath processing. This +// filename form is suitable for use in object files and export data. +// +// If b's filename has already been trimmed (i.e., because it was read +// in from an imported package's export data), then the filename is +// returned unchanged. +func trimFilename(b *syntax.PosBase) string { + filename := b.Filename() + if !b.Trimmed() { + dir := "" + if b.IsFileBase() { + dir = base.Ctxt.Pathname + } + filename = objabi.AbsFile(dir, filename, base.Flag.TrimPath) + } + return filename +} + // TODO(gri) Can we eliminate fileh in favor of absFilename? func fileh(name string) string { return objabi.AbsFile("", name, base.Flag.TrimPath) @@ -1690,8 +1709,14 @@ func (p *noder) pragma(pos syntax.Pos, blankLine bool, text string, old syntax.P // contain cgo directives, and for security reasons // (primarily misuse of linker flags), other files are not. // See golang.org/issue/23672. +// Note that cmd/go ignores files whose names start with underscore, +// so the only _cgo_ files we will see from cmd/go are generated by cgo. +// It's easy to bypass this check by calling the compiler directly; +// we only protect against uses by cmd/go. func isCgoGeneratedFile(pos syntax.Pos) bool { - return strings.HasPrefix(filepath.Base(filepath.Clean(fileh(pos.Base().Filename()))), "_cgo_") + // We need the absolute file, independent of //line directives, + // so we call pos.Base().Pos(). + return strings.HasPrefix(filepath.Base(trimFilename(pos.Base().Pos().Base())), "_cgo_") } // safeArg reports whether arg is a "safe" command-line argument, diff --git a/src/cmd/compile/internal/syntax/parser.go b/src/cmd/compile/internal/syntax/parser.go index e7b8840b337..4667e26a13b 100644 --- a/src/cmd/compile/internal/syntax/parser.go +++ b/src/cmd/compile/internal/syntax/parser.go @@ -146,11 +146,13 @@ func (p *parser) updateBase(pos Pos, tline, tcol uint, text string) { // If we have a column (//line filename:line:col form), // an empty filename means to use the previous filename. filename := text[:i-1] // lop off ":line" + trimmed := false if filename == "" && ok2 { filename = p.base.Filename() + trimmed = p.base.Trimmed() } - p.base = NewLineBase(pos, filename, line, col) + p.base = NewLineBase(pos, filename, trimmed, line, col) } func commentText(s string) string { diff --git a/src/cmd/compile/internal/syntax/pos.go b/src/cmd/compile/internal/syntax/pos.go index baebcc995c7..5dbd569b3f6 100644 --- a/src/cmd/compile/internal/syntax/pos.go +++ b/src/cmd/compile/internal/syntax/pos.go @@ -133,15 +133,21 @@ type PosBase struct { pos Pos filename string line, col uint32 + trimmed bool // whether -trimpath has been applied } // NewFileBase returns a new PosBase for the given filename. // A file PosBase's position is relative to itself, with the // position being filename:1:1. func NewFileBase(filename string) *PosBase { - base := &PosBase{MakePos(nil, linebase, colbase), filename, linebase, colbase} - base.pos.base = base - return base + return NewTrimmedFileBase(filename, false) +} + +// NewTrimmedFileBase is like NewFileBase, but allows specifying Trimmed. +func NewTrimmedFileBase(filename string, trimmed bool) *PosBase { + base := &PosBase{MakePos(nil, linebase, colbase), filename, linebase, colbase, trimmed} + base.pos.base = base + return base } // NewLineBase returns a new PosBase for a line directive "line filename:line:col" @@ -149,8 +155,8 @@ func NewFileBase(filename string) *PosBase { // the comment containing the line directive. For a directive in a line comment, // that position is the beginning of the next line (i.e., the newline character // belongs to the line comment). -func NewLineBase(pos Pos, filename string, line, col uint) *PosBase { - return &PosBase{pos, filename, sat32(line), sat32(col)} +func NewLineBase(pos Pos, filename string, trimmed bool, line, col uint) *PosBase { + return &PosBase{pos, filename, sat32(line), sat32(col), trimmed} } func (base *PosBase) IsFileBase() bool { @@ -188,6 +194,15 @@ func (base *PosBase) Col() uint { return uint(base.col) } +func (base *PosBase) Trimmed() bool { + if base == nil { + return false + } + return base.trimmed +} + + + func sat32(x uint) uint32 { if x > PosMax { return PosMax