Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

x/sys/unix: OpenBSD's Pledge and Unveil functions can be annulled #60322

Open
codesoap opened this issue May 20, 2023 · 6 comments
Open

x/sys/unix: OpenBSD's Pledge and Unveil functions can be annulled #60322

codesoap opened this issue May 20, 2023 · 6 comments
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. FeatureRequest help wanted NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. OS-OpenBSD
Milestone

Comments

@codesoap
Copy link
Contributor

What version of Go are you using (go version)?

$ go version
go version go1.20.1 openbsd/amd64

Does this issue reproduce with the latest release?

Yes.

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/path/to/.cache/go-build"
GOENV="/path/to/.config/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="openbsd"
GOINSECURE=""
GOMODCACHE="/path/to/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="openbsd"
GOPATH="/path/to/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/openbsd_amd64"
GOVCS=""
GOVERSION="go1.20.1"
GCCGO="gccgo"
GOAMD64="v1"
AR="ar"
CC="cc"
CXX="c++"
CGO_ENABLED="1"
GOMOD="/path/to/foo/go.mod"
GOWORK=""
CGO_CFLAGS="-O2 -g"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-O2 -g"
CGO_FFLAGS="-O2 -g"
CGO_LDFLAGS="-O2 -g"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -Wl,--no-gc-sections -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build1212173938=/tmp/go-build -gno-record-gcc-switches"

What did you do?

I ran this program:

package main

import "foo/bar"
import "golang.org/x/sys/unix"

func main() {
        if err := unix.Pledge("", ""); err != nil {
		panic(err)
	}
        bar.Greet()
}

Where the package bar contains this source file:

package bar

func init()  { println("Initializing bar.") }
func Greet() { println("Greetings from bar!") }

What did you expect to see?

I didn't really expect it, but ideally the program would exit immediately, because the unix.Pledge call didn't allow the use of standard IO and bar.init is printing something to the standard output.

In C programs, pledge is often called as the first thing in the main function, to prevent any code (written by the author themself or the author of a used library) to use undesired syscalls. Because in Go the init function of used libraries/packages are always executed before the init function and variable declarations of the main package, I see no way to replicate this C pattern in Go. Thus unix.Pledge cannot provide the same safety guarantees in Go as in C.

I suspect this is a problem that cannot be solved without a change in the language. I think there should at least be a warning in the documentation of the Pledge, PledgeExecpromises and PledgePromises, but also Unveil and UnveilBlock functions.

If there is a way to force Go to execute unix.Pledge as the first thing in a program, I'm gladly taking instructions on how to do this.

What did you see instead?

The program ran the init function of the bar package, before running unix.Pledge:

$ go run .
Initializing bar.
signal: abort trap (core dumped)
@gopherbot gopherbot added the compiler/runtime Issues related to the Go compiler and/or runtime. label May 20, 2023
@gopherbot gopherbot added this to the Unreleased milestone May 20, 2023
@seankhliao
Copy link
Member

cc @golang/openbsd

@seankhliao seankhliao added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label May 21, 2023
@bcmills
Copy link
Contributor

bcmills commented May 22, 2023

If there is a way to force Go to execute unix.Pledge as the first thing in a program, I'm gladly taking instructions on how to do this.

The only way I am aware of is to move the call to pledge into an early constructor function in a cgo library dependency.
(In GNU C that would be __attribute__((constructor(200))); I'm not sure about other dialects.)

Beyond that, you could try putting the call in an init function in a Go package that happens to be initialized before the other packages in the program. But it's not entirely clear to me how to ensure that (see also #57411).

@codesoap
Copy link
Contributor Author

codesoap commented May 23, 2023

Thanks for your input, @bcmills. I'm not very familiar with cgo, but it sounds like it could help here. However, if any other dependency uses cgo as well, it could probably also introduce some code, that is executed early.

@mknyszek
Copy link
Contributor

I'm not sure what we can do here, really. We should document it, at least.

@mknyszek
Copy link
Contributor

In triage a few people note that one way to achieve this is to pledge behavior could be to provide a function that forks and pledges before the exec. Then the child will start with the pledge you wanted?

@mknyszek
Copy link
Contributor

My bad, it would be a new option in syscall.SysProcAttr, probably.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. FeatureRequest help wanted NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. OS-OpenBSD
Projects
Development

No branches or pull requests

5 participants