diff --git a/runsc/boot/procfs/dump.go b/runsc/boot/procfs/dump.go index 3cc627607..2bbd1626b 100644 --- a/runsc/boot/procfs/dump.go +++ b/runsc/boot/procfs/dump.go @@ -38,11 +38,26 @@ type FDInfo struct { Path string `json:"path,omitempty"` } +// UIDGID contains information for /proc/[pid]/status/{uid,gid}. +type UIDGID struct { + Real uint32 `json:"real,omitempty"` + Effective uint32 `json:"effective,omitempty"` + Saved uint32 `json:"saved,omitempty"` +} + +// Status contains information for /proc/[pid]/status. +type Status struct { + Comm string `json:"comm,omitempty"` + PID int32 `json:"pid,omitempty"` + UID UIDGID `json:"uid,omitempty"` + GID UIDGID `json:"gid,omitempty"` + VMSize uint64 `json:"vm_size,omitempty"` + VMRSS uint64 `json:"vm_rss,omitempty"` +} + // ProcessProcfsDump contains the procfs dump for one process. For more details // on fields that directly correspond to /proc fields, see proc(5). type ProcessProcfsDump struct { - // PID is the process ID. - PID int32 `json:"pid,omitempty"` // Exe is the symlink target of /proc/[pid]/exe. Exe string `json:"exe,omitempty"` // Args is /proc/[pid]/cmdline split into an array. @@ -63,6 +78,8 @@ type ProcessProcfsDump struct { Limits map[string]limits.Limit `json:"limits,omitempty"` // Cgroup is /proc/[pid]/cgroup split into an array. Cgroup []kernel.TaskCgroupEntry `json:"cgroup,omitempty"` + // Status is /proc/[pid]/status. + Status Status `json:"status,omitempty"` } // getMM returns t's MemoryManager. On success, the MemoryManager's users count @@ -183,6 +200,27 @@ func getFDLimit(ctx context.Context, pid kernel.ThreadID) (limits.Limit, error) return limits.Limit{}, fmt.Errorf("could not find limit set for pid %s", pid) } +func getStatus(t *kernel.Task, mm *mm.MemoryManager, pid kernel.ThreadID) Status { + creds := t.Credentials() + uns := creds.UserNamespace + return Status{ + Comm: t.Name(), + PID: int32(pid), + UID: UIDGID{ + Real: uint32(creds.RealKUID.In(uns).OrOverflow()), + Effective: uint32(creds.EffectiveKUID.In(uns).OrOverflow()), + Saved: uint32(creds.SavedKUID.In(uns).OrOverflow()), + }, + GID: UIDGID{ + Real: uint32(creds.RealKGID.In(uns).OrOverflow()), + Effective: uint32(creds.EffectiveKGID.In(uns).OrOverflow()), + Saved: uint32(creds.SavedKGID.In(uns).OrOverflow()), + }, + VMSize: mm.VirtualMemorySize() >> 10, + VMRSS: mm.ResidentSetSize() >> 10, + } +} + // 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() @@ -199,7 +237,6 @@ func Dump(t *kernel.Task, pid kernel.ThreadID) (ProcessProcfsDump, error) { } return ProcessProcfsDump{ - PID: int32(pid), Exe: getExecutablePath(ctx, pid, mm), Args: getMetadataArray(ctx, pid, mm, proc.Cmdline), Env: getMetadataArray(ctx, pid, mm, proc.Environ), @@ -213,5 +250,6 @@ func Dump(t *kernel.Task, pid kernel.ThreadID) (ProcessProcfsDump, error) { // We don't need to worry about fake cgroup controllers as that is not // supported in runsc. Cgroup: t.GetCgroupEntries(), + Status: getStatus(t, mm, pid), }, nil } diff --git a/runsc/container/trace_test.go b/runsc/container/trace_test.go index fc0844b99..353de58e1 100644 --- a/runsc/container/trace_test.go +++ b/runsc/container/trace_test.go @@ -339,8 +339,8 @@ func TestProcfsDump(t *testing.T) { } // Sleep should be PID 1. - if procfsDump[0].PID != 1 { - t.Errorf("expected sleep process to be pid 1, got %d", procfsDump[0].PID) + if procfsDump[0].Status.PID != 1 { + t.Errorf("expected sleep process to be pid 1, got %d", procfsDump[0].Status.PID) } // Check that bin/sleep is part of the executable path. @@ -412,4 +412,22 @@ func TestProcfsDump(t *testing.T) { } } } + + if wantName := "sleep"; procfsDump[0].Status.Comm != wantName { + t.Errorf("expected Comm to be %q, but got %q", wantName, procfsDump[0].Status.Comm) + } + + if uid := procfsDump[0].Status.UID; uid.Real != 0 || uid.Effective != 0 || uid.Saved != 0 { + t.Errorf("expected UIDs to be 0 (root), got %+v", uid) + } + if gid := procfsDump[0].Status.GID; gid.Real != 0 || gid.Effective != 0 || gid.Saved != 0 { + t.Errorf("expected GIDs to be 0 (root), got %+v", gid) + } + + if procfsDump[0].Status.VMSize == 0 { + t.Errorf("expected VMSize to be set") + } + if procfsDump[0].Status.VMRSS == 0 { + t.Errorf("expected VMSize to be set") + } }