go: internal/poll: CopyFileRange returns EPERM on CircleCI Docker Host running 4.10.0-40-generic
What version of Go are you using (go version
)?
$ go version go version go1.15 linux/amd64
Does this issue reproduce with the latest release?
Yes
What operating system and processor architecture are you using (go env
)?
Docker Host running Ubuntu 18.04
on Linux Kernel 4.10.0-40-generic
This is the Go env of the container trying to build:
go env
Output
$ go env GO111MODULE="" GOARCH="amd64" GOBIN="" GOCACHE="/home/circleci/.cache/go-build" GOENV="/home/circleci/.config/go/env" GOEXE="" GOFLAGS="" GOHOSTARCH="amd64" GOHOSTOS="linux" GOINSECURE="" GOMODCACHE="/home/circleci/go/pkg/mod" GONOPROXY="" GONOSUMDB="" GOOS="linux" GOPATH="/home/circleci/go" GOPRIVATE="" GOPROXY="https://proxy.golang.org,direct" GOROOT="/usr/local/go" GOSUMDB="sum.golang.org" GOTMPDIR="" GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64" GCCGO="gccgo" AR="ar" CC="gcc" CXX="g++" CGO_ENABLED="1" GOMOD="/home/circleci/project/go.mod" CGO_CFLAGS="-g -O2" CGO_CPPFLAGS="" CGO_CXXFLAGS="-g -O2" CGO_FFLAGS="-g -O2" CGO_LDFLAGS="-g -O2" PKG_CONFIG="pkg-config" GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build612039276=/tmp/go-build -gno-record-gcc-switches"
What did you do?
I tried to build a Go binary (with Go 1.15) within a Docker container (from gimg/go:1.15) running on a CircleCI remote Docker engine (17.11.0-ce
).
What did you expect to see?
Docker image should have been built correctly, and my binary compiled successfully with Go 1.15.
What did you see instead?
An error like this for every binary in my project:
/usr/local/go/pkg/tool/linux_amd64/link: cannot write /tmp/go-link-518048351/000003.o: write /tmp/go-link-518048351/000003.o: copy_file_range: operation not permitted
/usr/local/go/pkg/tool/linux_amd64/link: cannot write /tmp/go-link-518048351/000035.o: write /tmp/go-link-518048351/000035.o: copy_file_range: operation not permitted
The command '/bin/bash -exo pipefail -c go install -mod=vendor -v ./...' returned a non-zero code: 2
Details from my investigation:
I build my binaries on CircleCI in a Docker container. CircleCI allows the user to pin a specific Docker engine, but they default to a version (17.11.0-ce) that runs on a Docker Host powered by Linux Kernel 4.10.0-40-generic
.
Despite the above kernel does support the directive copy_file_range
, for some restrictions possibly setup by the vendor, the Go linker gets this error:
usr/local/go/pkg/tool/linux_amd64/link: cannot write /tmp/go-link-518048351/000003.o: write /tmp/go-link-518048351/000003.o: copy_file_range: operation not permitted
This seems to correspond to the EPERM
error.
I’ve filed an issue report with the vendor asking why this is happening and I’m waiting for a confirmation: is this a scenario that we would like to take into account, and fallback as well to the other approach?
I assume the EPERM
can be returned also in the case of the user not having access to a file, therefore between the two branches of this switch I guess this scenario would be more similar to the second case where we might want a one-off fallback.
I spawn up a VirtualBox environment and tried to build the same code that breaks on CircleCI on three different kernels and all the builds were successful, proving that the issue I’ve encountered is probably related to some limitation/sandboxing artificially imposed by the vendor:
4.15.0-45-generic
<- the officially LTS supported by Ubuntu 16.044.10.0-40-generic
<- the one used by CircleCI4.4.232-0404232-generic
<- the latest prior to the introduction ofcopy_file_range
Unfortunately I can’t really reproduce the exact setup as CircleCI has its own internal AMIs/images that are not accessible to me, but I asked for the Kernel details and they told me the Docker Host that breaks my linker/builds runs on 4.10.0-40-generic
.
The above has been posted as a comment on https://github.com/golang/go/issues/40731 but for easier traceability I’ve opened a dedicated issue.
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Reactions: 1
- Comments: 15 (11 by maintainers)
Commits related to this issue
- Use mesos image to build binaries Use newer base kernel as recommended in https://github.com/golang/go/issues/40893 — committed to janisz/dcos-cli by janisz 4 years ago
- Use mesos image to build binaries Use newer base kernel as recommended in https://github.com/golang/go/issues/40893 — committed to janisz/dcos-cli by janisz 4 years ago
- Update Go to 1.15 (#1552) * Set minimum TLS version to 1.2 It's now the industry standard to deprecate TLS 1.0 and 1.1. See: https://tools.ietf.org/html/draft-ietf-tls-oldversions-deprecate-00 ... — committed to dcos/dcos-cli by janisz 4 years ago
- [release-branch.go1.15] internal/poll: treat copy_file_range EPERM as not-handled Updates #40893. Fixes #40900. Change-Id: I938ea4796c1e1d1e136117fe78b06ad6da8e40de Reviewed-on: https://go-review.go... — committed to golang/go by tklauser 4 years ago
- interfaces/seccomp/template.go: allow copy_file_range This was recently introduced as an optimization to Go 1.15, and so apps that start compiling may start to try and use it. Note that as of this c... — committed to anonymouse64/snapd by anonymouse64 4 years ago
- interfaces/seccomp/template.go: allow copy_file_range This was recently introduced as an optimization to Go 1.15, and so apps that start compiling may start to try and use it. Note that as of this c... — committed to anonymouse64/snapd by anonymouse64 4 years ago
- interfaces/seccomp/template.go: allow copy_file_range This was recently introduced as an optimization to Go 1.15, and so apps that start compiling may start to try and use it. Note that as of this c... — committed to anonymouse64/snapd by anonymouse64 4 years ago
- interfaces/seccomp/template.go: allow copy_file_range This was recently introduced as an optimization to Go 1.15, and so apps that start compiling may start to try and use it. Note that Go 1.15 does... — committed to anonymouse64/snapd by anonymouse64 4 years ago
- interfaces/seccomp/template.go: allow copy_file_range This was recently introduced as an optimization to Go 1.15, and so apps that start compiling may start to try and use it. Note that Go 1.15 does... — committed to anonymouse64/snapd by anonymouse64 4 years ago
- Merge pull request #9702 from anonymouse64/feature/copy_file_range-seccomp-default interfaces/seccomp/template.go: allow copy_file_range This was recently introduced as an optimization to Go 1.15,... — committed to snapcore/snapd by anonymouse64 3 years ago
- interfaces/seccomp/template.go: allow copy_file_range This was recently introduced as an optimization to Go 1.15, and so apps that start compiling may start to try and use it. Note that Go 1.15 does... — committed to snapcore/snapd by anonymouse64 4 years ago
- Attempt to fix build error Related to https://github.com/golang/go/issues/40893 The command "npm run export" generates an error, because it uses the unimplemented syscall "copyfile". This commit att... — committed to openmaraude/console by brmzkw 3 years ago
Also paging @tianon who knows more about this stuff than the rest of us put together.
fyi, I followed this advice from https://discuss.circleci.com/t/cgo-docker-build-failing-at-link-stage-operation-not-permitted/37100 and it fixed my similar issue:
Sorry, got the answer already:
Ahh, so this could also be related to the version of libseccomp that their build of 17.11.0-ce is compiled against. 😅
(See also https://github.com/moby/moby/issues/40734 for a recent example of newer kernel APIs being blocked by default thanks to that.)
If you can run with the equivalent of
--security-opt seccomp:unconfined
, that would be a good test to confirm.Change https://golang.org/cl/249257 mentions this issue:
internal/poll: treat copy_file_range EPERM as not-handled
Given the error (and what’s already been ruled out 💪), my initial guess would be seccomp or apparmor related – does CircleCI use a profile for either of those that’s more restrictive than Docker’s defaults? Maybe some extra capabilities they drop?