diff options
author | Daniel J Walsh <dwalsh@redhat.com> | 2018-08-16 12:10:23 -0400 |
---|---|---|
committer | Atomic Bot <atomic-devel@projectatomic.io> | 2018-08-16 18:28:44 +0000 |
commit | 37e3f47ef3ecc6f36fca65f47914139c636f34ac (patch) | |
tree | c36333ed6494db5a763313aa4a1b0b61369b8d49 /vendor | |
parent | d20f3a51463ce75d139dd830e19a173906b0b0cb (diff) | |
download | podman-37e3f47ef3ecc6f36fca65f47914139c636f34ac.tar.gz podman-37e3f47ef3ecc6f36fca65f47914139c636f34ac.tar.bz2 podman-37e3f47ef3ecc6f36fca65f47914139c636f34ac.zip |
Vendor in latest containers/psgo code
This fixes a couple of issues with podman top.
podman top --latest USER HUSER
Now shows you the User inside of the containers usernamespace as well as the user on the host.
podman top --latest capeff capbnd
Now has headings that differentiatiate between the Capabiltiies. We also have support for
ambient capabilities.
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
Closes: #1286
Approved by: vrothberg
Diffstat (limited to 'vendor')
6 files changed, 107 insertions, 22 deletions
diff --git a/vendor/github.com/containers/psgo/README.md b/vendor/github.com/containers/psgo/README.md index 7b779b539..6b0f1dab3 100644 --- a/vendor/github.com/containers/psgo/README.md +++ b/vendor/github.com/containers/psgo/README.md @@ -46,6 +46,8 @@ root 1 0 0.000 17.249905587s ? 0s sleep ### Format descriptors The ps library is compatible with all AIX format descriptors of the ps command-line utility (see `man 1 ps` for details) but it also supports some additional descriptors that can be useful when seeking specific process-related information. +- **capamb** + - Set of ambient capabilities. See capabilities(7) for more information. - **capbnd** - Set of bounding capabilities. See capabilities(7) for more information. - **capeff** diff --git a/vendor/github.com/containers/psgo/internal/proc/ns.go b/vendor/github.com/containers/psgo/internal/proc/ns.go index 61b4b2b58..fbfbd4894 100644 --- a/vendor/github.com/containers/psgo/internal/proc/ns.go +++ b/vendor/github.com/containers/psgo/internal/proc/ns.go @@ -13,3 +13,12 @@ func ParsePIDNamespace(pid string) (string, error) { } return pidNS, nil } + +// ParseUserNamespace returns the content of /proc/$pid/ns/user. +func ParseUserNamespace(pid string) (string, error) { + userNS, err := os.Readlink(fmt.Sprintf("/proc/%s/ns/user", pid)) + if err != nil { + return "", err + } + return userNS, nil +} diff --git a/vendor/github.com/containers/psgo/internal/proc/status.go b/vendor/github.com/containers/psgo/internal/proc/status.go index b8e06dd6b..364d9e9a2 100644 --- a/vendor/github.com/containers/psgo/internal/proc/status.go +++ b/vendor/github.com/containers/psgo/internal/proc/status.go @@ -4,8 +4,10 @@ import ( "bufio" "fmt" "os" + "os/exec" "strings" + "github.com/containers/psgo/internal/types" "github.com/pkg/errors" ) @@ -160,8 +162,24 @@ type Status struct { NonvoluntaryCtxtSwitches string } -// readStatus is used for mocking in unit tests. -var readStatus = func(path string) ([]string, error) { +// readStatusUserNS joins the user namespace of pid and returns the content of +// /proc/pid/status as a string slice. +func readStatusUserNS(pid string) ([]string, error) { + path := fmt.Sprintf("/proc/%s/status", pid) + args := []string{"nsenter", "-U", "-t", pid, "cat", path} + + c := exec.Command(args[0], args[1:]...) + output, err := c.CombinedOutput() + if err != nil { + return nil, fmt.Errorf("error executing %q: %v", strings.Join(args, " "), err) + } + + return strings.Split(string(output), "\n"), nil +} + +// readStatusDefault returns the content of /proc/pid/status as a string slice. +func readStatusDefault(pid string) ([]string, error) { + path := fmt.Sprintf("/proc/%s/status", pid) f, err := os.Open(path) if err != nil { return nil, err @@ -175,15 +193,26 @@ var readStatus = func(path string) ([]string, error) { } // ParseStatus parses the /proc/$pid/status file and returns a *Status. -func ParseStatus(pid string) (*Status, error) { - path := fmt.Sprintf("/proc/%s/status", pid) - lines, err := readStatus(path) +func ParseStatus(ctx *types.PsContext, pid string) (*Status, error) { + var lines []string + var err error + + if ctx.JoinUserNS { + lines, err = readStatusUserNS(pid) + } else { + lines, err = readStatusDefault(pid) + } + if err != nil { return nil, err } + return parseStatus(pid, lines) +} +// parseStatus extracts data from lines and returns a *Status. +func parseStatus(pid string, lines []string) (*Status, error) { s := Status{} - errUnexpectedInput := errors.New(fmt.Sprintf("unexpected input from %s", path)) + errUnexpectedInput := fmt.Errorf("unexpected input from /proc/%s/status", pid) for _, line := range lines { fields := strings.Fields(line) if len(fields) < 2 { diff --git a/vendor/github.com/containers/psgo/internal/process/process.go b/vendor/github.com/containers/psgo/internal/process/process.go index b1ea076b5..6a8dfb0c0 100644 --- a/vendor/github.com/containers/psgo/internal/process/process.go +++ b/vendor/github.com/containers/psgo/internal/process/process.go @@ -7,6 +7,7 @@ import ( "github.com/containers/psgo/internal/host" "github.com/containers/psgo/internal/proc" + "github.com/containers/psgo/internal/types" "github.com/opencontainers/runc/libcontainer/user" "github.com/pkg/errors" ) @@ -61,13 +62,13 @@ func LookupUID(uid string) (string, error) { // New returns a new Process with the specified pid and parses the relevant // data from /proc and /dev. -func New(pid string) (*Process, error) { +func New(ctx *types.PsContext, pid string) (*Process, error) { p := Process{Pid: pid} if err := p.parseStat(); err != nil { return nil, err } - if err := p.parseStatus(); err != nil { + if err := p.parseStatus(ctx); err != nil { return nil, err } if err := p.parseCmdLine(); err != nil { @@ -88,10 +89,10 @@ func New(pid string) (*Process, error) { } // FromPIDs creates a new Process for each pid. -func FromPIDs(pids []string) ([]*Process, error) { +func FromPIDs(ctx *types.PsContext, pids []string) ([]*Process, error) { processes := []*Process{} for _, pid := range pids { - p, err := New(pid) + p, err := New(ctx, pid) if err != nil { if os.IsNotExist(err) { // proc parsing is racy @@ -116,8 +117,8 @@ func (p *Process) parseStat() error { } // parseStatus parses /proc/$pid/status. -func (p *Process) parseStatus() error { - s, err := proc.ParseStatus(p.Pid) +func (p *Process) parseStatus(ctx *types.PsContext) error { + s, err := proc.ParseStatus(ctx, p.Pid) if err != nil { return err } @@ -135,7 +136,7 @@ func (p *Process) parseCmdLine() error { return nil } -// parsePIDNamespace parses all host-related data fields. +// parsePIDNamespace sets the PID namespace. func (p *Process) parsePIDNamespace() error { pidNS, err := proc.ParsePIDNamespace(p.Pid) if err != nil { diff --git a/vendor/github.com/containers/psgo/internal/types/types.go b/vendor/github.com/containers/psgo/internal/types/types.go new file mode 100644 index 000000000..9069e8000 --- /dev/null +++ b/vendor/github.com/containers/psgo/internal/types/types.go @@ -0,0 +1,8 @@ +package types + +// PsContext controls some internals of the psgo library. +type PsContext struct { + // JoinUserNS will force /proc and /dev parsing from within each PIDs + // user namespace. + JoinUserNS bool +} diff --git a/vendor/github.com/containers/psgo/psgo.go b/vendor/github.com/containers/psgo/psgo.go index e52089b3c..2ea9a322b 100644 --- a/vendor/github.com/containers/psgo/psgo.go +++ b/vendor/github.com/containers/psgo/psgo.go @@ -25,6 +25,7 @@ import ( "github.com/containers/psgo/internal/dev" "github.com/containers/psgo/internal/proc" "github.com/containers/psgo/internal/process" + "github.com/containers/psgo/internal/types" "github.com/pkg/errors" "golang.org/x/sys/unix" ) @@ -183,23 +184,28 @@ var ( procFn: processVSZ, }, { + normal: "capamb", + header: "AMBIENT CAPS", + procFn: processCAPAMB, + }, + { normal: "capinh", - header: "CAPABILITIES", + header: "INHERITED CAPS", procFn: processCAPINH, }, { normal: "capprm", - header: "CAPABILITIES", + header: "PERMITTED CAPS", procFn: processCAPPRM, }, { normal: "capeff", - header: "CAPABILITIES", + header: "EFFECTIVE CAPS", procFn: processCAPEFF, }, { normal: "capbnd", - header: "CAPABILITIES", + header: "BOUNDING CAPS", procFn: processCAPBND, }, { @@ -276,6 +282,19 @@ func JoinNamespaceAndProcessInfo(pid string, descriptors []string) ([][]string, defer wg.Done() runtime.LockOSThread() + // extract user namespaces prior to joining the mount namespace + currentUserNs, err := proc.ParseUserNamespace("self") + if err != nil { + dataErr = errors.Wrapf(err, "error determining user namespace") + return + } + + pidUserNs, err := proc.ParseUserNamespace(pid) + if err != nil { + dataErr = errors.Wrapf(err, "error determining user namespace of PID %s", pid) + } + + // join the mount namespace of pid fd, err := os.Open(fmt.Sprintf("/proc/%s/ns/mnt", pid)) if err != nil { dataErr = err @@ -290,12 +309,19 @@ func JoinNamespaceAndProcessInfo(pid string, descriptors []string) ([][]string, } unix.Setns(int(fd.Fd()), unix.CLONE_NEWNS) + // extract all pids mentioned in pid's mount namespace pids, err := proc.GetPIDs() if err != nil { dataErr = err return } - processes, err := process.FromPIDs(pids) + + ctx := types.PsContext{ + // join the user NS if the pid's user NS is different + // to the caller's user NS. + JoinUserNS: currentUserNs != pidUserNs, + } + processes, err := process.FromPIDs(&ctx, pids) if err != nil { dataErr = err return @@ -324,7 +350,9 @@ func ProcessInfo(descriptors []string) ([][]string, error) { if err != nil { return nil, err } - processes, err := process.FromPIDs(pids) + + ctx := types.PsContext{JoinUserNS: false} + processes, err := process.FromPIDs(&ctx, pids) if err != nil { return nil, err } @@ -340,7 +368,8 @@ func setHostProcesses(pid string) error { return err } - processes, err := process.FromPIDs(pids) + ctx := types.PsContext{JoinUserNS: false} + processes, err := process.FromPIDs(&ctx, pids) if err != nil { return err } @@ -421,14 +450,14 @@ func processPPID(p *process.Process) (string, error) { } // processUSER returns the effective user name of the process. This will be -// the textual group ID, if it can be optained, or a decimal representation +// the textual user ID, if it can be optained, or a decimal representation // otherwise. func processUSER(p *process.Process) (string, error) { return process.LookupUID(p.Status.Uids[1]) } // processRUSER returns the effective user name of the process. This will be -// the textual group ID, if it can be optained, or a decimal representation +// the textual user ID, if it can be optained, or a decimal representation // otherwise. func processRUSER(p *process.Process) (string, error) { return process.LookupUID(p.Status.Uids[0]) @@ -557,6 +586,13 @@ func parseCAP(cap string) (string, error) { return strings.Join(caps, ","), nil } +// processCAPAMB returns the set of ambient capabilties associated with +// process p. If all capabilties are set, "full" is returned. If no +// capability is enabled, "none" is returned. +func processCAPAMB(p *process.Process) (string, error) { + return parseCAP(p.Status.CapAmb) +} + // processCAPINH returns the set of inheritable capabilties associated with // process p. If all capabilties are set, "full" is returned. If no // capability is enabled, "none" is returned. |