aboutsummaryrefslogtreecommitdiff
path: root/src/runtime
diff options
context:
space:
mode:
authorCherry Mui <cherryyz@google.com>2024-05-14 00:01:49 -0400
committerCherry Mui <cherryyz@google.com>2024-05-15 19:57:43 +0000
commitc4772d30bfbed6cfbfdf92066990b5c6dc4065bb (patch)
tree0b3c762ff38080831c20aff0d8ef9020fa698620 /src/runtime
parent849770dec9191475ffed23f0d0985d8222c51e53 (diff)
downloadgo-c4772d30bfbed6cfbfdf92066990b5c6dc4065bb.tar.gz
go-c4772d30bfbed6cfbfdf92066990b5c6dc4065bb.zip
cmd/link: disallow pull-only linknames
As mentioned in CL 584598, linkname is a mechanism that, when abused, can break API integrity and even safety of Go programs. CL 584598 is a first step to restrict the use of linknames, by implementing a blocklist. This CL takes a step further, tightening up the restriction by allowing linkname references ("pull") only when the definition side explicitly opts into it, by having a linkname on the definition (possibly to itself). This way, it is at least clear on the definition side that the symbol, despite being unexported, is accessed outside of the package. Unexported symbols without linkname can now be actually private. This is similar to the symbol visibility rule used by gccgo for years (which defines unexported non-linknamed symbols as C static symbols). As there can be pull-only linknames in the wild that may be broken by this change, we currently only enforce this rule for symbols defined in the standard library. Push linknames are added in the standard library to allow things build. Linkname references to external (non-Go) symbols are still allowed, as their visibility is controlled by the C symbol visibility rules and enforced by the C (static or dynamic) linker. Assembly symbols are treated similar to linknamed symbols. This is controlled by -checklinkname linker flag, currently not enabled by default. A follow-up CL will enable it by default. Change-Id: I07344f5c7a02124dbbef0fbc8fec3b666a4b2b0e Reviewed-on: https://go-review.googlesource.com/c/go/+/585358 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Than McIntosh <thanm@google.com> Reviewed-by: Russ Cox <rsc@golang.org>
Diffstat (limited to 'src/runtime')
-rw-r--r--src/runtime/coro.go2
-rw-r--r--src/runtime/coverage/emit.go3
-rw-r--r--src/runtime/coverage/testsupport.go6
-rw-r--r--src/runtime/linkname.go49
-rw-r--r--src/runtime/linkname_unix.go12
-rw-r--r--src/runtime/netpoll.go3
-rw-r--r--src/runtime/string.go2
-rw-r--r--src/runtime/vdso_linux_amd64.go5
8 files changed, 79 insertions, 3 deletions
diff --git a/src/runtime/coro.go b/src/runtime/coro.go
index 98e789f133..b2bc801940 100644
--- a/src/runtime/coro.go
+++ b/src/runtime/coro.go
@@ -46,8 +46,6 @@ func newcoro(f func(*coro)) *coro {
return c
}
-//go:linkname corostart
-
// corostart is the entry func for a new coroutine.
// It runs the coroutine user function f passed to corostart
// and then calls coroexit to remove the extra concurrency.
diff --git a/src/runtime/coverage/emit.go b/src/runtime/coverage/emit.go
index 6fe04daea8..6510c889ea 100644
--- a/src/runtime/coverage/emit.go
+++ b/src/runtime/coverage/emit.go
@@ -574,6 +574,9 @@ func (s *emitState) emitCounterDataFile(finalHash [16]byte, w io.Writer) error {
return nil
}
+// markProfileEmitted is injected to testmain via linkname.
+//go:linkname markProfileEmitted
+
// markProfileEmitted signals the runtime/coverage machinery that
// coverage data output files have already been written out, and there
// is no need to take any additional action at exit time. This
diff --git a/src/runtime/coverage/testsupport.go b/src/runtime/coverage/testsupport.go
index 4b00f3a0f7..b673d3cd2c 100644
--- a/src/runtime/coverage/testsupport.go
+++ b/src/runtime/coverage/testsupport.go
@@ -22,6 +22,9 @@ import (
"unsafe"
)
+// processCoverTestDir is injected in testmain.
+//go:linkname processCoverTestDir
+
// processCoverTestDir is called (via a linknamed reference) from
// testmain code when "go test -cover" is in effect. It is not
// intended to be used other than internally by the Go command's
@@ -277,6 +280,9 @@ func (ts *tstate) readAuxMetaFiles(metafiles string, importpaths map[string]stru
return nil
}
+// snapshot is injected in testmain.
+//go:linkname snapshot
+
// snapshot returns a snapshot of coverage percentage at a moment of
// time within a running test, so as to support the testing.Coverage()
// function. This version doesn't examine coverage meta-data, so the
diff --git a/src/runtime/linkname.go b/src/runtime/linkname.go
new file mode 100644
index 0000000000..0f02c6b4e3
--- /dev/null
+++ b/src/runtime/linkname.go
@@ -0,0 +1,49 @@
+// Copyright 2024 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 runtime
+
+import _ "unsafe"
+
+// used in time and internal/poll
+//go:linkname nanotime
+
+// used in internal/godebug and syscall
+//go:linkname write
+
+// used in internal/runtime/atomic
+//go:linkname goarm
+
+// used by cgo
+//go:linkname cgocall
+//go:linkname _cgo_panic_internal
+//go:linkname cgoAlwaysFalse
+//go:linkname cgoUse
+//go:linkname cgoCheckPointer
+//go:linkname cgoCheckResult
+//go:linkname cgoNoCallback
+//go:linkname gobytes
+//go:linkname gostringn
+//go:linkname throw
+
+// used in plugin
+//go:linkname doInit
+
+// used in math/bits
+//go:linkname overflowError
+//go:linkname divideError
+
+// used in runtime/coverage and in tests
+//go:linkname addExitHook
+
+// used in x/sys/cpu
+//go:linkname getAuxv
+
+// used in tests
+//go:linkname extraMInUse
+//go:linkname getm
+//go:linkname blockevent
+//go:linkname haveHighResSleep
+//go:linkname blockUntilEmptyFinalizerQueue
+//go:linkname lockedOSThread
diff --git a/src/runtime/linkname_unix.go b/src/runtime/linkname_unix.go
new file mode 100644
index 0000000000..65f876fa4b
--- /dev/null
+++ b/src/runtime/linkname_unix.go
@@ -0,0 +1,12 @@
+// Copyright 2024 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.
+
+//go:build unix
+
+package runtime
+
+import _ "unsafe"
+
+// used in internal/syscall/unix
+//go:linkname fcntl
diff --git a/src/runtime/netpoll.go b/src/runtime/netpoll.go
index bbfef80aec..7b37d91b24 100644
--- a/src/runtime/netpoll.go
+++ b/src/runtime/netpoll.go
@@ -207,6 +207,9 @@ var (
netpollWaiters atomic.Uint32
)
+// netpollWaiters is accessed in tests
+//go:linkname netpollWaiters
+
//go:linkname poll_runtime_pollServerInit internal/poll.runtime_pollServerInit
func poll_runtime_pollServerInit() {
netpollGenericInit()
diff --git a/src/runtime/string.go b/src/runtime/string.go
index e01b7fc744..81d1b80e56 100644
--- a/src/runtime/string.go
+++ b/src/runtime/string.go
@@ -312,7 +312,7 @@ func gobytes(p *byte, n int) (b []byte) {
return
}
-// This is exported via linkname to assembly in syscall (for Plan9).
+// This is exported via linkname to assembly in syscall (for Plan9) and cgo.
//
//go:linkname gostring
func gostring(p *byte) string {
diff --git a/src/runtime/vdso_linux_amd64.go b/src/runtime/vdso_linux_amd64.go
index 4e9f748f4a..9c56409137 100644
--- a/src/runtime/vdso_linux_amd64.go
+++ b/src/runtime/vdso_linux_amd64.go
@@ -4,6 +4,8 @@
package runtime
+import _ "unsafe" // for linkname
+
const (
// vdsoArrayMax is the byte-size of a maximally sized array on this architecture.
// See cmd/compile/internal/amd64/galign.go arch.MAXWIDTH initialization.
@@ -21,3 +23,6 @@ var (
vdsoGettimeofdaySym uintptr
vdsoClockgettimeSym uintptr
)
+
+// vdsoGettimeofdaySym is accessed from the syscall package.
+//go:linkname vdsoGettimeofdaySym