aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/noder
diff options
context:
space:
mode:
authorCherry Mui <cherryyz@google.com>2024-05-09 17:07:43 -0400
committerCherry Mui <cherryyz@google.com>2024-05-10 17:05:33 +0000
commit4721f95058878042576ef09562a84e6c93e5c399 (patch)
tree17540e917269a8631701ee3ab33f38c0c45d4b9a /src/cmd/compile/internal/noder
parentdf4f40b9e07ed9b4d50dc10a445d4b50c37e4daa (diff)
downloadgo-4721f95058878042576ef09562a84e6c93e5c399.tar.xz
cmd/compile, cmd/link: disallow linkname of some newly added internal functions
Go API is defined through exported symbols. When a package is imported, the compiler ensures that only exported symbols can be accessed, and the go command ensures that internal packages cannot be imported. This ensures API integrity. But there is a hole: using linkname, one can access internal or non-exported symbols. Linkname is a mechanism to give access of a symbol to a package without adding it to the public API. It is intended for coupled packages to share some implementation details, or to break circular dependencies, and both "push" (definition) and "pull" (reference) sides are controlled, so they can be updated in sync. Nevertheless, it is abused as a mechanism to reach into internal details of other packages uncontrolled by the user, notably the runtime. As the other package evolves, the code often breaks, because the linknamed symbol may no longer exist, or change its signature or semantics. This CL adds a mechanism to enforce the integrity of linknames. Generally, "push" linkname is allowed, as the package defining the symbol explicitly opt in for access outside of the package. "Pull" linkname is checked and only allowed in some circumstances. Given that there are existing code that use "pull"-only linkname to access other package's internals, disallowing it completely is too much a change at this point in the release cycle. For a start, implement a hard-coded blocklist, which contains some newly added internal functions that, if used inappropriately, may break memory safety or runtime integrity. All blocked symbols are newly added in Go 1.23. So existing code that builds with Go 1.22 will continue to build. For the implementation, when compiling a package, we mark linknamed symbols in the current package with an attribute. At link time, marked linknamed symbols are checked against the blocklist. Care is taken so it distinguishes a linkname reference in the current package vs. a reference of a linkname from another package and propagated to the current package (e.g. through inlining or instantiation). Symbol references in assembly code are similar to linknames, and are treated similarly. Change-Id: I8067efe29c122740cd4f1effd2dec2d839147d5d Reviewed-on: https://go-review.googlesource.com/c/go/+/584598 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Than McIntosh <thanm@google.com> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Diffstat (limited to 'src/cmd/compile/internal/noder')
-rw-r--r--src/cmd/compile/internal/noder/reader.go13
1 files changed, 12 insertions, 1 deletions
diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go
index c33e5226f3..abd07ebb62 100644
--- a/src/cmd/compile/internal/noder/reader.go
+++ b/src/cmd/compile/internal/noder/reader.go
@@ -1176,7 +1176,18 @@ func (r *reader) linkname(name *ir.Name) {
lsym.SymIdx = int32(idx)
lsym.Set(obj.AttrIndexed, true)
} else {
- name.Sym().Linkname = r.String()
+ linkname := r.String()
+ sym := name.Sym()
+ sym.Linkname = linkname
+ if sym.Pkg == types.LocalPkg && linkname != "" {
+ // Mark linkname in the current package. We don't mark the
+ // ones that are imported and propagated (e.g. through
+ // inlining or instantiation, which are marked in their
+ // corresponding packages). So we can tell in which package
+ // the linkname is used (pulled), and the linker can
+ // make a decision for allowing or disallowing it.
+ sym.Linksym().Set(obj.AttrLinkname, true)
+ }
}
}