diff --git a/pkg/sentry/limits/limits.go b/pkg/sentry/limits/limits.go index 7c6c4df01..6dd726e02 100644 --- a/pkg/sentry/limits/limits.go +++ b/pkg/sentry/limits/limits.go @@ -51,9 +51,9 @@ const Infinity = ^uint64(0) // +stateify savable type Limit struct { // Cur specifies the current limit. - Cur uint64 + Cur uint64 `json:"cur,omitempty"` // Max specifies the maximum settable limit. - Max uint64 + Max uint64 `json:"max,omitempty"` } // LimitSet represents the Limits that correspond to each LimitType. diff --git a/runsc/boot/procfs/BUILD b/runsc/boot/procfs/BUILD index 4b7950206..cf06480bd 100644 --- a/runsc/boot/procfs/BUILD +++ b/runsc/boot/procfs/BUILD @@ -11,6 +11,7 @@ go_library( "//pkg/log", "//pkg/sentry/fsimpl/proc", "//pkg/sentry/kernel", + "//pkg/sentry/limits", "//pkg/sentry/mm", "//pkg/sentry/vfs", ], diff --git a/runsc/boot/procfs/dump.go b/runsc/boot/procfs/dump.go index 19a9ff72c..17c2829be 100644 --- a/runsc/boot/procfs/dump.go +++ b/runsc/boot/procfs/dump.go @@ -25,6 +25,7 @@ import ( "gvisor.dev/gvisor/pkg/log" "gvisor.dev/gvisor/pkg/sentry/fsimpl/proc" "gvisor.dev/gvisor/pkg/sentry/kernel" + "gvisor.dev/gvisor/pkg/sentry/limits" "gvisor.dev/gvisor/pkg/sentry/mm" "gvisor.dev/gvisor/pkg/sentry/vfs" ) @@ -57,6 +58,9 @@ type ProcessProcfsDump struct { StartTime int64 `json:"clone_ts,omitempty"` // Root is /proc/[pid]/root. Root string `json:"root,omitempty"` + // Limits constains resource limits for this process. Currently only + // RLIMIT_NOFILE is supported. + Limits map[string]limits.Limit `json:"limits,omitempty"` } // getMM returns t's MemoryManager. On success, the MemoryManager's users count @@ -170,6 +174,13 @@ func getRoot(t *kernel.Task, pid kernel.ThreadID) string { return path } +func getFDLimit(ctx context.Context, pid kernel.ThreadID) (limits.Limit, error) { + if limitSet := limits.FromContext(ctx); limitSet != nil { + return limitSet.Get(limits.NumberOfFiles), nil + } + return limits.Limit{}, fmt.Errorf("could not find limit set for pid %s", pid) +} + // Dump returns a procfs dump for process pid. t must be a task in process pid. func Dump(t *kernel.Task, pid kernel.ThreadID) (ProcessProcfsDump, error) { ctx := t.AsyncContext() @@ -180,6 +191,11 @@ func Dump(t *kernel.Task, pid kernel.ThreadID) (ProcessProcfsDump, error) { } defer mm.DecUsers(ctx) + fdLimit, err := getFDLimit(ctx, pid) + if err != nil { + return ProcessProcfsDump{}, err + } + return ProcessProcfsDump{ PID: int32(pid), Exe: getExecutablePath(ctx, pid, mm), @@ -189,5 +205,8 @@ func Dump(t *kernel.Task, pid kernel.ThreadID) (ProcessProcfsDump, error) { FDs: getFDs(ctx, t, pid), StartTime: t.StartTime().Nanoseconds(), Root: getRoot(t, pid), + Limits: map[string]limits.Limit{ + "RLIMIT_NOFILE": fdLimit, + }, }, nil } diff --git a/runsc/container/BUILD b/runsc/container/BUILD index 04fdd0c1d..1173df328 100644 --- a/runsc/container/BUILD +++ b/runsc/container/BUILD @@ -70,6 +70,7 @@ go_test( "//pkg/sentry/control", "//pkg/sentry/kernel", "//pkg/sentry/kernel/auth", + "//pkg/sentry/limits", "//pkg/sentry/platform", "//pkg/sentry/seccheck", "//pkg/sentry/seccheck/checkers/remote/test", diff --git a/runsc/container/trace_test.go b/runsc/container/trace_test.go index 3b7d61c10..c492ba032 100644 --- a/runsc/container/trace_test.go +++ b/runsc/container/trace_test.go @@ -21,7 +21,9 @@ import ( "testing" "time" + specs "github.com/opencontainers/runtime-spec/specs-go" "google.golang.org/protobuf/proto" + "gvisor.dev/gvisor/pkg/sentry/limits" "gvisor.dev/gvisor/pkg/sentry/seccheck" "gvisor.dev/gvisor/pkg/sentry/seccheck/checkers/remote/test" pb "gvisor.dev/gvisor/pkg/sentry/seccheck/points/points_go_proto" @@ -295,6 +297,13 @@ func TestProcfsDump(t *testing.T) { testEnv := "GVISOR_IS_GREAT=true" spec.Process.Env = append(spec.Process.Env, testEnv) spec.Process.Cwd = "/" + fdLimit := limits.Limit{ + Cur: 10_000, + Max: 100_000, + } + spec.Process.Rlimits = []specs.POSIXRlimit{ + {Type: "RLIMIT_NOFILE", Hard: fdLimit.Max, Soft: fdLimit.Cur}, + } _, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf) if err != nil { t.Fatalf("error setting up container: %v", err) @@ -383,4 +392,8 @@ func TestProcfsDump(t *testing.T) { if want := "/"; procfsDump[0].Root != "/" { t.Errorf("expected root to be %q, but got %q", want, procfsDump[0].Root) } + + if got := procfsDump[0].Limits["RLIMIT_NOFILE"]; got != fdLimit { + t.Errorf("expected FD limit to be %+v, but got %+v", fdLimit, got) + } }