]> Cypherpunks repositories - gostls13.git/commitdiff
syscall: don't change local limit if prlimit used for another process
authorlifubang <lifubang@acmcoder.com>
Fri, 10 May 2024 03:29:45 +0000 (03:29 +0000)
committerGopher Robot <gobot@golang.org>
Mon, 13 May 2024 21:18:19 +0000 (21:18 +0000)
Fixes: #67184
Change-Id: Ibdf3810cbba30ae29f466f7f95f357e8512f228b
GitHub-Last-Rev: 5eabc760be6b89ae85629627da37b517e8ec356f
GitHub-Pull-Request: golang/go#67185
Reviewed-on: https://go-review.googlesource.com/c/go/+/583299
Reviewed-by: Ian Lance Taylor <iant@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Auto-Submit: Ian Lance Taylor <iant@google.com>

src/syscall/export_linux_test.go
src/syscall/export_rlimit_test.go
src/syscall/syscall_linux.go
src/syscall/syscall_linux_test.go

index 9bcf73e771910e609e994a01100ecd909f38d161..d9309bf234e14deea9ebfade9cfef3b338223586 100644 (file)
@@ -11,6 +11,7 @@ import (
 var (
        RawSyscallNoError = rawSyscallNoError
        ForceClone3       = &forceClone3
+       Prlimit           = prlimit
 )
 
 const (
index 8b1545cb0390985e364b3e2e98487211976add72..f584ac410dc042bba33838e5552723749f727969 100644 (file)
@@ -6,6 +6,12 @@
 
 package syscall
 
+import "sync/atomic"
+
 func OrigRlimitNofile() *Rlimit {
        return origRlimitNofile.Load()
 }
+
+func GetInternalOrigRlimitNofile() *atomic.Pointer[Rlimit] {
+       return &origRlimitNofile
+}
index 6547c517a71179adffcf90a5a894150ad367666b..f35e78c26af33a617ffdb6816579af85c9232589 100644 (file)
@@ -1289,7 +1289,7 @@ func Munmap(b []byte) (err error) {
 // This is unexported but can be called from x/sys/unix.
 func prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) {
        err = prlimit1(pid, resource, newlimit, old)
-       if err == nil && newlimit != nil && resource == RLIMIT_NOFILE {
+       if err == nil && newlimit != nil && resource == RLIMIT_NOFILE && (pid == 0 || pid == Getpid()) {
                origRlimitNofile.Store(nil)
        }
        return err
index 1300fc046e9b1e3fc51d3887e79a714aca113e6c..675406fba01de24f555ed1136f810995890a9c9d 100644 (file)
@@ -654,3 +654,69 @@ func TestAllThreadsSyscallBlockedSyscall(t *testing.T) {
        wr.Close()
        wg.Wait()
 }
+
+func TestPrlimitSelf(t *testing.T) {
+       origLimit := syscall.OrigRlimitNofile()
+       origRlimitNofile := syscall.GetInternalOrigRlimitNofile()
+
+       if origLimit == nil {
+               defer origRlimitNofile.Store(origLimit)
+               origRlimitNofile.Store(&syscall.Rlimit{
+                       Cur: 1024,
+                       Max: 65536,
+               })
+       }
+
+       // Get current process's nofile limit
+       var lim syscall.Rlimit
+       if err := syscall.Prlimit(0, syscall.RLIMIT_NOFILE, nil, &lim); err != nil {
+               t.Fatalf("Failed to get the current nofile limit: %v", err)
+       }
+       // Set current process's nofile limit through prlimit
+       if err := syscall.Prlimit(0, syscall.RLIMIT_NOFILE, &lim, nil); err != nil {
+               t.Fatalf("Prlimit self failed: %v", err)
+       }
+
+       rlimLater := origRlimitNofile.Load()
+       if rlimLater != nil {
+               t.Fatalf("origRlimitNofile got=%v, want=nil", rlimLater)
+       }
+}
+
+func TestPrlimitOtherProcess(t *testing.T) {
+       origLimit := syscall.OrigRlimitNofile()
+       origRlimitNofile := syscall.GetInternalOrigRlimitNofile()
+
+       if origLimit == nil {
+               defer origRlimitNofile.Store(origLimit)
+               origRlimitNofile.Store(&syscall.Rlimit{
+                       Cur: 1024,
+                       Max: 65536,
+               })
+       }
+       rlimOrig := origRlimitNofile.Load()
+
+       // Start a child process firstly,
+       // so we can use Prlimit to set it's nofile limit.
+       cmd := exec.Command("sleep", "infinity")
+       cmd.Start()
+       defer func() {
+               cmd.Process.Kill()
+               cmd.Process.Wait()
+       }()
+
+       // Get child process's current nofile limit
+       var lim syscall.Rlimit
+       if err := syscall.Prlimit(cmd.Process.Pid, syscall.RLIMIT_NOFILE, nil, &lim); err != nil {
+               t.Fatalf("Failed to get the current nofile limit: %v", err)
+       }
+       // Set child process's nofile rlimit through prlimit
+       if err := syscall.Prlimit(cmd.Process.Pid, syscall.RLIMIT_NOFILE, &lim, nil); err != nil {
+               t.Fatalf("Prlimit(%d) failed: %v", cmd.Process.Pid, err)
+       }
+
+       rlimLater := origRlimitNofile.Load()
+       if rlimLater != rlimOrig {
+               t.Fatalf("origRlimitNofile got=%v, want=%v", rlimLater, rlimOrig)
+       }
+}