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

syscall: Getrlimit test failures in docker on armv7 / aarch64 #38604

Closed
Ikke opened this issue Apr 22, 2020 · 11 comments
Closed

syscall: Getrlimit test failures in docker on armv7 / aarch64 #38604

Ikke opened this issue Apr 22, 2020 · 11 comments

Comments

@Ikke
Copy link

@Ikke Ikke commented Apr 22, 2020

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

$ go version
go version go1.13.10 linux/arm64

Does this issue reproduce with the latest release?

Yes, 1.14.2 still failes

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

Alpine Linux in docker on Alpine Linux on armv7 / aarch64

go env Output
$ go env
GO111MODULE=""
GOARCH="arm64"
GOBIN=""
GOCACHE="/home/buildozer/.cache/go-build"
GOENV="/home/buildozer/.config/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="arm64"
GOHOSTOS="linux"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/home/buildozer/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/lib/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/lib/go/pkg/tool/linux_arm64"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build704765024=/tmp/go-build -gno-record-gcc-switches"

What did you do?

Build golang and run the test suite in a docker container on either armv7 or aarch64

See our APKBUILD for details

What did you expect to see?

Test suite pass

What did you see instead?

 --- FAIL: TestRlimit (0.00s)
    syscall_unix_test.go:332: Getrlimit: save failed: operation not permitted
FAIL
FAIL	syscall	0.029s

Build log

This doesn't happen when we build / run the test suite in a privileged container.

@Ikke
Copy link
Author

@Ikke Ikke commented Apr 22, 2020

It runs fine on other arches (x86, x86_64, ppc64le, s390x)

@andybons
Copy link
Member

@andybons andybons commented Apr 23, 2020

Does the following C program print the resource limits or also fail with an error?

#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <sys/resource.h>

int main() {
  struct rlimit lim;
  if (getrlimit(RLIMIT_NOFILE, &lim) == 0) {
    printf(
        "limit = %llu\n"
        "hard limit = %llu\n",
        lim.rlim_cur, lim.rlim_max);
  } else {
    fprintf(stderr, "%s\n", strerror(errno));
  }
  return 0;
}
@andybons andybons added this to the Unplanned milestone Apr 23, 2020
@andybons andybons changed the title Getrlimit test failures in docker on armv7 / aarch64 syscall: Getrlimit test failures in docker on armv7 / aarch64 Apr 23, 2020
@Ikke
Copy link
Author

@Ikke Ikke commented Apr 24, 2020

That works, yes:

~ $ cat test_getrlimit.c                                                                                               
#include <errno.h>                                                                                                     
#include <stdio.h>                                                                                                     
#include <string.h>                                                                                                    
#include <sys/resource.h>                                                                                              
                                                                                                                       
int main() {                                                                                                           
  struct rlimit lim;                                                                                                   
  if (getrlimit(RLIMIT_NOFILE, &lim) == 0) {                                                                           
    printf(                                                                                                            
        "limit = %llu\n"                                                                                               
        "hard limit = %llu\n",                                                                                         
        lim.rlim_cur, lim.rlim_max);                                                                                   
  } else {                                                                                                             
    fprintf(stderr, "%s\n", strerror(errno));                                                                          
  }                                                                                                                    
  return 0;                                                                                                            
}                                                                                                                      
                                                                                                                       
~ $ gcc test_getrlimit.c -o test_getrlimit                                                                             
~ $ ./test_getrlimit                                                                                                   
limit = 1048576                                                                                                        
hard limit = 1048576
$ uname -a
Linux 2ba79cdd745c 5.4.34-0-virt #1-Alpine SMP Wed. 22 Apr 2020 19:26:07 UTC aarch65 Linux
@andybons
Copy link
Member

@andybons andybons commented Apr 24, 2020

@ianlancetaylor any thoughts?

@ianlancetaylor
Copy link
Contributor

@ianlancetaylor ianlancetaylor commented Apr 24, 2020

Can you run both the C program and the Go program under strace -f, and see exactly which system calls they are using for getrlimit? Thanks.

@Ikke
Copy link
Author

@Ikke Ikke commented Apr 26, 2020

This is the golang test that is failing (I show the last part of the output of the process that is calling getrlimit)

~ $ PATH=$PWD/bin:$PATH strace -f -s520 -o testrlimit.strace go test -v syscall -run TestRlimit
4822  write(1, "=== RUN   TestRlimit\n", 21 
4822  <... write resumed>)              = 21
4822  futex(0x40000aa148, FUTEX_WAKE_PRIVATE, 1 
4822  <... futex resumed>)              = 0
4822  getrlimit(RLIMIT_NOFILE,  
4822  <... getrlimit resumed>0x400007ced8) = -1 EPERM (Operation not permitted)
4822  write(1, "--- FAIL: TestRlimit (0.00s)\n", 29 
4822  <... write resumed>)              = 29
4822  write(1, "    syscall_unix_test.go:332: Getrlimit: save failed: operation not permitted\n", 78 
4822  <... write resumed>)              = 78
4822  futex(0x40000aa148, FUTEX_WAKE_PRIVATE, 1 
4822  <... futex resumed>)              = 1
4822  write(1, "FAIL\n", 5 
4822  <... write resumed>)              = 5
4822  write(3, "# test log\n", 11 
4822  <... write resumed>)              = 11
4822  close(3 
4822  <... close resumed>)              = 0
4822  exit_group(1 
4822  <... exit_group resumed>)         = ?
4822  +++ exited with 1 +++

This is the test program provided by @andybons

~ $ strace -f -s 512 -o test_getrlimit.strace ./test_getrlimit
4843  execve("./test_getrlimit", ["./test_getrlimit"], 0xffffe8cd4d28 /* 7 vars */) = 0
4843  set_tid_address(0xffffb99220c4)   = 4843
4843  mprotect(0xaaaabafcb000, 4096, PROT_READ) = 0
4843  prlimit64(0, RLIMIT_NOFILE, NULL, {rlim_cur=1024*1024, rlim_max=1024*1024}) = 0
4843  ioctl(1, TIOCGWINSZ, {ws_row=64, ws_col=239, ws_xpixel=0, ws_ypixel=0}) = 0
4843  writev(1, [{iov_base="limit = 1048576", iov_len=15}, {iov_base="\n", iov_len=1}], 2) = 16
4843  writev(1, [{iov_base="hard limit = 1048576", iov_len=20}, {iov_base="\n", iov_len=1}], 2) = 21
4843  exit_group(0)                     = ?
4843  +++ exited with 0 +++

So golang is calling getrlimit, which gets permission denied, while the test program calls prlimit64, which succeeds.

@gopherbot
Copy link

@gopherbot gopherbot commented Apr 28, 2020

Change https://golang.org/cl/230339 mentions this issue: syscall: on linux-arm64, prefer prlimit to {g,s}etrlimit

@ianlancetaylor
Copy link
Contributor

@ianlancetaylor ianlancetaylor commented Apr 28, 2020

Thanks for the info. Can you see if https://golang.org/cl/230339 fixes the problem for you?

@Ikke
Copy link
Author

@Ikke Ikke commented Apr 28, 2020

@ianlancetaylor Yes, I can confirm this patch fixes the issue, all tests succeed now.

@gopherbot
Copy link

@gopherbot gopherbot commented Apr 28, 2020

Change https://golang.org/cl/230478 mentions this issue: unix: on linux-arm64, prefer prlimit to {g,s}etrlimit

gopherbot pushed a commit to golang/sys that referenced this issue Apr 28, 2020
Do the same as CL 230339 did for package syscall:

Reportedly some Docker images accept the prlimit64 system call,
used by syscall.prlimit, but prohibit the getrlimit and setrlimit
system calls.

Updates golang/go#38604

Change-Id: I4fc9197d7b037c2f375e50b149701316a36023f3
Reviewed-on: https://go-review.googlesource.com/c/sys/+/230478
Run-TryBot: Tobias Klauser <tobias.klauser@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
@gopherbot gopherbot closed this in b255c12 Apr 30, 2020
xujianhai666 added a commit to xujianhai666/go-1 that referenced this issue May 21, 2020
Reportedly some Docker images accept the prlimit64 system call,
used by syscall.prlimit, but prohibit the getrlimit and setrlimit
system calls.

Fixes golang#38604

Change-Id: I91ff9370450b4869098cc8e335bbb7b863060508
Reviewed-on: https://go-review.googlesource.com/c/go/+/230339
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-by: Tobias Klauser <tobias.klauser@gmail.com>
algitbot pushed a commit to alpinelinux/aports that referenced this issue Jun 1, 2020
@tianon
Copy link
Contributor

@tianon tianon commented Nov 5, 2020

For the curious, the root cause of this denial is a bug in libseccomp where it wrongly presumed getrlimit didn't exist on these ARM arches: seccomp/libseccomp#234 (apparently fixed in libseccomp 2.4.4).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
5 participants
You can’t perform that action at this time.