diff options
author | Fabricio Voznika <fvoznika@google.com> | 2021-06-10 13:47:43 -0700 |
---|---|---|
committer | gVisor bot <gvisor-bot@google.com> | 2021-06-10 13:55:10 -0700 |
commit | d81fcbf85c771a75bcf6600a02b3d411c6f7e383 (patch) | |
tree | 7637774c682f7717ca1389f0db9bac11027ce548 /runsc | |
parent | 21169357ca913de9cef50da6f235a482b7a3cfab (diff) |
Set RLimits during `runsc exec`
PiperOrigin-RevId: 378726430
Diffstat (limited to 'runsc')
-rw-r--r-- | runsc/boot/loader.go | 7 | ||||
-rw-r--r-- | runsc/container/container_test.go | 141 |
2 files changed, 109 insertions, 39 deletions
diff --git a/runsc/boot/loader.go b/runsc/boot/loader.go index 111d30154..ad4d50008 100644 --- a/runsc/boot/loader.go +++ b/runsc/boot/loader.go @@ -963,10 +963,15 @@ func (l *Loader) executeAsync(args *control.ExecArgs) (kernel.ThreadID, error) { } args.Envv = envv } + args.PIDNamespace = tg.PIDNamespace() + + args.Limits, err = createLimitSet(l.root.spec) + if err != nil { + return 0, fmt.Errorf("creating limits: %w", err) + } // Start the process. proc := control.Proc{Kernel: l.k} - args.PIDNamespace = tg.PIDNamespace() newTG, tgid, ttyFile, ttyFileVFS2, err := control.ExecAsync(&proc, args) if err != nil { return 0, err diff --git a/runsc/container/container_test.go b/runsc/container/container_test.go index 0e79877b7..249324c5a 100644 --- a/runsc/container/container_test.go +++ b/runsc/container/container_test.go @@ -47,6 +47,62 @@ import ( "gvisor.dev/gvisor/runsc/specutils" ) +func TestMain(m *testing.M) { + log.SetLevel(log.Debug) + flag.Parse() + if err := testutil.ConfigureExePath(); err != nil { + panic(err.Error()) + } + specutils.MaybeRunAsRoot() + os.Exit(m.Run()) +} + +func execute(cont *Container, name string, arg ...string) (unix.WaitStatus, error) { + args := &control.ExecArgs{ + Filename: name, + Argv: append([]string{name}, arg...), + } + return cont.executeSync(args) +} + +func executeCombinedOutput(cont *Container, name string, arg ...string) ([]byte, error) { + r, w, err := os.Pipe() + if err != nil { + return nil, err + } + defer r.Close() + + args := &control.ExecArgs{ + Filename: name, + Argv: append([]string{name}, arg...), + FilePayload: urpc.FilePayload{Files: []*os.File{os.Stdin, w, w}}, + } + ws, err := cont.executeSync(args) + w.Close() + if err != nil { + return nil, err + } + if ws != 0 { + return nil, fmt.Errorf("exec failed, status: %v", ws) + } + + out, err := ioutil.ReadAll(r) + return out, err +} + +// executeSync synchronously executes a new process. +func (c *Container) executeSync(args *control.ExecArgs) (unix.WaitStatus, error) { + pid, err := c.Execute(args) + if err != nil { + return 0, fmt.Errorf("error executing: %v", err) + } + ws, err := c.WaitPID(pid) + if err != nil { + return 0, fmt.Errorf("error waiting: %v", err) + } + return ws, nil +} + // waitForProcessList waits for the given process list to show up in the container. func waitForProcessList(cont *Container, want []*control.Process) error { cb := func() error { @@ -2470,58 +2526,67 @@ func TestBindMountByOption(t *testing.T) { } } -func execute(cont *Container, name string, arg ...string) (unix.WaitStatus, error) { - args := &control.ExecArgs{ - Filename: name, - Argv: append([]string{name}, arg...), +// TestRlimits sets limit to number of open files and checks that the limit +// is propagated to the container. +func TestRlimits(t *testing.T) { + file, err := ioutil.TempFile(testutil.TmpDir(), "ulimit") + if err != nil { + t.Fatal(err) } - return cont.executeSync(args) -} + cmd := fmt.Sprintf("ulimit -n > %q", file.Name()) -func executeCombinedOutput(cont *Container, name string, arg ...string) ([]byte, error) { - r, w, err := os.Pipe() - if err != nil { - return nil, err + spec := testutil.NewSpecWithArgs("sh", "-c", cmd) + spec.Process.Rlimits = []specs.POSIXRlimit{ + {Type: "RLIMIT_NOFILE", Hard: 1000, Soft: 100}, } - defer r.Close() - args := &control.ExecArgs{ - Filename: name, - Argv: append([]string{name}, arg...), - FilePayload: urpc.FilePayload{Files: []*os.File{os.Stdin, w, w}}, + conf := testutil.TestConfig(t) + if err := run(spec, conf); err != nil { + t.Fatalf("Error running container: %v", err) } - ws, err := cont.executeSync(args) - w.Close() + got, err := ioutil.ReadFile(file.Name()) if err != nil { - return nil, err + t.Fatal(err) } - if ws != 0 { - return nil, fmt.Errorf("exec failed, status: %v", ws) + if want := "100\n"; string(got) != want { + t.Errorf("ulimit result, got: %q, want: %q", got, want) } - - out, err := ioutil.ReadAll(r) - return out, err } -// executeSync synchronously executes a new process. -func (c *Container) executeSync(args *control.ExecArgs) (unix.WaitStatus, error) { - pid, err := c.Execute(args) +// TestRlimitsExec sets limit to number of open files and checks that the limit +// is propagated to exec'd processes. +func TestRlimitsExec(t *testing.T) { + spec := testutil.NewSpecWithArgs("sleep", "100") + spec.Process.Rlimits = []specs.POSIXRlimit{ + {Type: "RLIMIT_NOFILE", Hard: 1000, Soft: 100}, + } + + conf := testutil.TestConfig(t) + _, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf) if err != nil { - return 0, fmt.Errorf("error executing: %v", err) + t.Fatalf("error setting up container: %v", err) } - ws, err := c.WaitPID(pid) + defer cleanup() + + args := Args{ + ID: testutil.RandomContainerID(), + Spec: spec, + BundleDir: bundleDir, + } + cont, err := New(conf, args) if err != nil { - return 0, fmt.Errorf("error waiting: %v", err) + t.Fatalf("error creating container: %v", err) + } + defer cont.Destroy() + if err := cont.Start(conf); err != nil { + t.Fatalf("error starting container: %v", err) } - return ws, nil -} -func TestMain(m *testing.M) { - log.SetLevel(log.Debug) - flag.Parse() - if err := testutil.ConfigureExePath(); err != nil { - panic(err.Error()) + got, err := executeCombinedOutput(cont, "/bin/sh", "-c", "ulimit -n") + if err != nil { + t.Fatal(err) + } + if want := "100\n"; string(got) != want { + t.Errorf("ulimit result, got: %q, want: %q", got, want) } - specutils.MaybeRunAsRoot() - os.Exit(m.Run()) } |