diff options
-rw-r--r-- | pkg/sentry/control/proc.go | 9 | ||||
-rw-r--r-- | runsc/boot/loader.go | 7 | ||||
-rw-r--r-- | runsc/container/container_test.go | 141 |
3 files changed, 117 insertions, 40 deletions
diff --git a/pkg/sentry/control/proc.go b/pkg/sentry/control/proc.go index 367849e75..221e98a01 100644 --- a/pkg/sentry/control/proc.go +++ b/pkg/sentry/control/proc.go @@ -99,6 +99,9 @@ type ExecArgs struct { // PIDNamespace is the pid namespace for the process being executed. PIDNamespace *kernel.PIDNamespace + + // Limits is the limit set for the process being executed. + Limits *limits.LimitSet } // String prints the arguments as a string. @@ -151,6 +154,10 @@ func (proc *Proc) execAsync(args *ExecArgs) (*kernel.ThreadGroup, kernel.ThreadI if pidns == nil { pidns = proc.Kernel.RootPIDNamespace() } + limitSet := args.Limits + if limitSet == nil { + limitSet = limits.NewLimitSet() + } initArgs := kernel.CreateProcessArgs{ Filename: args.Filename, Argv: args.Argv, @@ -161,7 +168,7 @@ func (proc *Proc) execAsync(args *ExecArgs) (*kernel.ThreadGroup, kernel.ThreadI Credentials: creds, FDTable: fdTable, Umask: 0022, - Limits: limits.NewLimitSet(), + Limits: limitSet, MaxSymlinkTraversals: linux.MaxSymlinkTraversals, UTSNamespace: proc.Kernel.RootUTSNamespace(), IPCNamespace: proc.Kernel.RootIPCNamespace(), 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()) } |