diff options
author | Cherry Mui <cherryyz@google.com> | 2024-05-14 00:01:49 -0400 |
---|---|---|
committer | Cherry Mui <cherryyz@google.com> | 2024-05-15 19:57:43 +0000 |
commit | c4772d30bfbed6cfbfdf92066990b5c6dc4065bb (patch) | |
tree | 0b3c762ff38080831c20aff0d8ef9020fa698620 /src/runtime | |
parent | 849770dec9191475ffed23f0d0985d8222c51e53 (diff) | |
download | go-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.go | 2 | ||||
-rw-r--r-- | src/runtime/coverage/emit.go | 3 | ||||
-rw-r--r-- | src/runtime/coverage/testsupport.go | 6 | ||||
-rw-r--r-- | src/runtime/linkname.go | 49 | ||||
-rw-r--r-- | src/runtime/linkname_unix.go | 12 | ||||
-rw-r--r-- | src/runtime/netpoll.go | 3 | ||||
-rw-r--r-- | src/runtime/string.go | 2 | ||||
-rw-r--r-- | src/runtime/vdso_linux_amd64.go | 5 |
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 |