summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml4
-rw-r--r--CONTRIBUTING.md73
-rw-r--r--Dockerfile2
-rw-r--r--cmd/podman/libpodruntime/runtime.go4
-rw-r--r--cmd/podman/ps.go20
-rw-r--r--cmd/podman/shared/container.go6
-rw-r--r--libpod/container_api.go25
-rw-r--r--libpod/container_attach.go18
-rw-r--r--libpod/container_internal.go56
-rw-r--r--libpod/container_internal_linux.go44
-rw-r--r--libpod/networking_linux.go28
-rw-r--r--libpod/runtime.go5
-rw-r--r--pkg/lookup/lookup.go156
13 files changed, 340 insertions, 101 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index 87842da74..ae660394b 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -20,7 +20,7 @@ env:
CNI_COMMIT: "7480240de9749f9a0a5c8614b17f1f03e0c06ab9"
CRIO_COMMIT: "662dbb31b5d4f5ed54511a47cde7190c61c28677"
CRIU_COMMIT: "584cbe4643c3fc7dc901ff08bf923ca0fe7326f9"
- RUNC_COMMIT: "ad0f5255060d36872be04de22f8731f38ef2d7b1"
+ RUNC_COMMIT: "78ef28e63bec2ee4c139b5e3e0d691eb9bdc748d"
# File to update in home-dir with task-specific env. var values
ENVLIB: ".bash_profile"
# Overrides default location (/tmp/cirrus) for repo clone
@@ -42,7 +42,7 @@ full_vm_testing_task:
# 'matrix' combinations. All run in parallel.
matrix:
# Images are generated separetly, from build_images_task (below)
- image_name: "ubuntu-1804-bionic-v20180911-libpod-fce09afe"
+ image_name: "ubuntu-1804-bionic-v20180911-libpod-63a86a18"
# TODO: Make these work (also build_images_task below)
#image_name: "rhel-server-ec2-7-5-165-1-libpod-fce09afe"
#image_name: "centos-7-v20180911-libpod-fce09afe"
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index fa95bfe3a..c4e208894 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -52,11 +52,80 @@ too since in the end the entire PR will be reviewed anyway. When in doubt,
squash.
PRs that fix issues should include a reference like `Closes #XXXX` in the
-commit message so that github will automatically close the referenced issue
+commit message so that GitHub will automatically close the referenced issue
when the PR is merged.
PRs will be approved by an [approver][owners] listed in [`OWNERS`](OWNERS).
+### Describe your Changes in Commit Messages
+
+Describe your problem. Whether your patch is a one-line bug fix or 5000 lines
+of a new feature, there must be an underlying problem that motivated you to do
+this work. Convince the reviewer that there is a problem worth fixing and that
+it makes sense for them to read past the first paragraph.
+
+Describe user-visible impact. Straight up crashes and lockups are pretty
+convincing, but not all bugs are that blatant. Even if the problem was spotted
+during code review, describe the impact you think it can have on users. Keep in
+mind that the majority of users run packages provided by distributions, so
+include anything that could help route your change downstream.
+
+Quantify optimizations and trade-offs. If you claim improvements in
+performance, memory consumption, stack footprint, or binary size, include
+numbers that back them up. But also describe non-obvious costs. Optimizations
+usually aren’t free but trade-offs between CPU, memory, and readability; or,
+when it comes to heuristics, between different workloads. Describe the expected
+downsides of your optimization so that the reviewer can weigh costs against
+benefits.
+
+Once the problem is established, describe what you are actually doing about it
+in technical detail. It’s important to describe the change in plain English for
+the reviewer to verify that the code is behaving as you intend it to.
+
+Solve only one problem per patch. If your description starts to get long,
+that’s a sign that you probably need to split up your patch.
+
+If the patch fixes a logged bug entry, refer to that bug entry by number and
+URL. If the patch follows from a mailing list discussion, give a URL to the
+mailing list archive.
+
+However, try to make your explanation understandable without external
+resources. In addition to giving a URL to a mailing list archive or bug,
+summarize the relevant points of the discussion that led to the patch as
+submitted.
+
+If you want to refer to a specific commit, don’t just refer to the SHA-1 ID of
+the commit. Please also include the oneline summary of the commit, to make it
+easier for reviewers to know what it is about. Example:
+
+```
+Commit f641c2d9384e ("fix bug in rm -fa parallel deletes") [...]
+```
+
+You should also be sure to use at least the first twelve characters of the
+SHA-1 ID. The libpod repository holds a lot of objects, making collisions with
+shorter IDs a real possibility. Bear in mind that, even if there is no
+collision with your six-character ID now, that condition may change five years
+from now.
+
+If your patch fixes a bug in a specific commit, e.g. you found an issue using
+git bisect, please use the ‘Fixes:’ tag with the first 12 characters of the
+SHA-1 ID, and the one line summary. For example:
+
+```
+Fixes: f641c2d9384e ("fix bug in rm -fa parallel deletes")
+```
+
+The following git config settings can be used to add a pretty format for
+outputting the above style in the git log or git show commands:
+
+```
+[core]
+ abbrev = 12
+[pretty]
+ fixes = Fixes: %h (\"%s\")
+```
+
### Sign your PRs
The sign-off is a line at the end of the explanation for the patch. Your
@@ -127,7 +196,7 @@ Integration Tests [README.md](test/README.md).
For general questions and discussion, please use the
IRC `#podman` channel on `irc.freenode.net`.
-For discussions around issues/bugs and features, you can use the github
+For discussions around issues/bugs and features, you can use the GitHub
[issues](https://github.com/containers/libpod/issues)
and
[PRs](https://github.com/containers/libpod/pulls)
diff --git a/Dockerfile b/Dockerfile
index 62be638f2..70d1a7629 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -52,7 +52,7 @@ ADD . /go/src/github.com/containers/libpod
RUN set -x && cd /go/src/github.com/containers/libpod && make install.libseccomp.sudo
# Install runc
-ENV RUNC_COMMIT ad0f5255060d36872be04de22f8731f38ef2d7b1
+ENV RUNC_COMMIT 78ef28e63bec2ee4c139b5e3e0d691eb9bdc748d
RUN set -x \
&& export GOPATH="$(mktemp -d)" \
&& git clone https://github.com/opencontainers/runc.git "$GOPATH/src/github.com/opencontainers/runc" \
diff --git a/cmd/podman/libpodruntime/runtime.go b/cmd/podman/libpodruntime/runtime.go
index df422eb81..a4b3581be 100644
--- a/cmd/podman/libpodruntime/runtime.go
+++ b/cmd/podman/libpodruntime/runtime.go
@@ -5,6 +5,7 @@ import (
"github.com/containers/libpod/pkg/rootless"
"github.com/containers/libpod/pkg/util"
"github.com/containers/storage"
+ "github.com/pkg/errors"
"github.com/urfave/cli"
)
@@ -42,6 +43,9 @@ func GetRuntimeWithStorageOpts(c *cli.Context, storageOpts *storage.StoreOptions
if c.GlobalIsSet("runroot") {
storageOpts.RunRoot = c.GlobalString("runroot")
}
+ if len(storageOpts.RunRoot) > 50 {
+ return nil, errors.New("the specified runroot is longer than 50 characters")
+ }
if c.GlobalIsSet("storage-driver") {
storageOpts.GraphDriverName = c.GlobalString("storage-driver")
}
diff --git a/cmd/podman/ps.go b/cmd/podman/ps.go
index d63618e58..83274c9a8 100644
--- a/cmd/podman/ps.go
+++ b/cmd/podman/ps.go
@@ -329,16 +329,12 @@ func psCmd(c *cli.Context) error {
}
// Define a tab writer with stdout as the output
- w := tabwriter.NewWriter(os.Stdout, 0, 0, 1, ' ', 0)
+ w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
defer w.Flush()
// Output standard PS headers
if !opts.Namespace {
- fmt.Fprintf(w, "\n%s\t%s\t%s\t%s\t%s\t%s\t%s", hid, himage, hcommand, hcreated, hstatus, hports, hnames)
- // If the user does not want size OR pod info, we print the isInfra bool
- if !opts.Size && !opts.Pod {
- fmt.Fprintf(w, "\t%s", hinfra)
- }
+ fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\t%s", hid, himage, hcommand, hcreated, hstatus, hports, hnames)
// User wants pod info
if opts.Pod {
fmt.Fprintf(w, "\t%s", hpod)
@@ -349,22 +345,15 @@ func psCmd(c *cli.Context) error {
}
} else {
// Output Namespace headers
- fmt.Fprintf(w, "\n%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s", hid, hnames, nspid, nscgroup, nsipc, nsmnt, nsnet, nspidns, nsuserns, nsuts)
- }
- if len(pss) == 0 {
- fmt.Fprint(w, "\n")
+ fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s", hid, hnames, nspid, nscgroup, nsipc, nsmnt, nsnet, nspidns, nsuserns, nsuts)
}
+
// Now iterate each container and output its information
for _, container := range pss {
// Standard PS output
if !opts.Namespace {
fmt.Fprintf(w, "\n%s\t%s\t%s\t%s\t%s\t%s\t%s", container.ID, container.Image, container.Command, container.Created, container.Status, container.Ports, container.Names)
-
- // If not size and not pod info, do isInfra
- if !opts.Size && !opts.Pod {
- fmt.Fprintf(w, "\t%t", container.IsInfra)
- }
// User wants pod info
if opts.Pod {
fmt.Fprintf(w, "\t%s", container.Pod)
@@ -387,6 +376,7 @@ func psCmd(c *cli.Context) error {
}
}
+ fmt.Fprint(w, "\n")
return nil
}
diff --git a/cmd/podman/shared/container.go b/cmd/podman/shared/container.go
index b847314a4..4404268d4 100644
--- a/cmd/podman/shared/container.go
+++ b/cmd/podman/shared/container.go
@@ -24,6 +24,7 @@ import (
const (
cidTruncLength = 12
podTruncLength = 12
+ cmdTruncLength = 17
)
// PsOptions describes the struct being formed for ps
@@ -191,9 +192,12 @@ func NewBatchContainer(ctr *libpod.Container, opts PsOptions) (PsContainerOutput
pod := ctr.PodID()
if !opts.NoTrunc {
cid = cid[0:cidTruncLength]
- if len(pod) > 12 {
+ if len(pod) > podTruncLength {
pod = pod[0:podTruncLength]
}
+ if len(command) > cmdTruncLength {
+ command = command[0:cmdTruncLength] + "..."
+ }
}
pso.ID = cid
diff --git a/libpod/container_api.go b/libpod/container_api.go
index 41a131ea2..30c67eb2a 100644
--- a/libpod/container_api.go
+++ b/libpod/container_api.go
@@ -10,8 +10,8 @@ import (
"time"
"github.com/containers/libpod/libpod/driver"
- "github.com/containers/libpod/pkg/chrootuser"
"github.com/containers/libpod/pkg/inspect"
+ "github.com/containers/libpod/pkg/lookup"
"github.com/containers/storage/pkg/stringid"
"github.com/docker/docker/daemon/caps"
"github.com/pkg/errors"
@@ -292,13 +292,13 @@ func (c *Container) Exec(tty, privileged bool, env, cmd []string, user string) e
// the host
hostUser := ""
if user != "" {
- uid, gid, err := chrootuser.GetUser(c.state.Mountpoint, user)
+ execUser, err := lookup.GetUserGroupInfo(c.state.Mountpoint, user, nil)
if err != nil {
- return errors.Wrapf(err, "error getting user to launch exec session as")
+ return err
}
// runc expects user formatted as uid:gid
- hostUser = fmt.Sprintf("%d:%d", uid, gid)
+ hostUser = fmt.Sprintf("%d:%d", execUser.Uid, execUser.Gid)
}
// Generate exec session ID
@@ -453,22 +453,19 @@ func (c *Container) Unmount(force bool) error {
}
}
- if c.state.State == ContainerStateRunning || c.state.State == ContainerStatePaused {
- return errors.Wrapf(ErrCtrStateInvalid, "cannot unmount storage for container %s as it is running or paused", c.ID())
- }
-
- // Check if we have active exec sessions
- if len(c.state.ExecSessions) != 0 {
- return errors.Wrapf(ErrCtrStateInvalid, "container %s has active exec sessions, refusing to unmount", c.ID())
- }
-
if c.state.Mounted {
mounted, err := c.runtime.storageService.MountedContainerImage(c.ID())
if err != nil {
return errors.Wrapf(err, "can't determine how many times %s is mounted, refusing to unmount", c.ID())
}
if mounted == 1 {
- return errors.Wrapf(err, "can't unmount %s last mount, it is still in use", c.ID())
+ if c.state.State == ContainerStateRunning || c.state.State == ContainerStatePaused {
+ return errors.Wrapf(ErrCtrStateInvalid, "cannot unmount storage for container %s as it is running or paused", c.ID())
+ }
+ if len(c.state.ExecSessions) != 0 {
+ return errors.Wrapf(ErrCtrStateInvalid, "container %s has active exec sessions, refusing to unmount", c.ID())
+ }
+ return errors.Wrapf(ErrInternal, "can't unmount %s last mount, it is still in use", c.ID())
}
}
return c.unmount(force)
diff --git a/libpod/container_attach.go b/libpod/container_attach.go
index 3c4e0775d..f925c3897 100644
--- a/libpod/container_attach.go
+++ b/libpod/container_attach.go
@@ -16,6 +16,10 @@ import (
"k8s.io/client-go/tools/remotecommand"
)
+//#include <sys/un.h>
+// extern int unix_path_length(){struct sockaddr_un addr; return sizeof(addr.sun_path) - 1;}
+import "C"
+
/* Sync with stdpipe_t in conmon.c */
const (
AttachPipeStdin = 1
@@ -81,11 +85,19 @@ func (c *Container) attachContainerSocket(resize <-chan remotecommand.TerminalSi
logrus.Warnf("Failed to write to control file to resize terminal: %v", err)
}
})
- logrus.Debug("connecting to socket ", c.AttachSocketPath())
- conn, err := net.DialUnix("unixpacket", nil, &net.UnixAddr{Name: c.AttachSocketPath(), Net: "unixpacket"})
+ socketPath := c.AttachSocketPath()
+
+ maxUnixLength := int(C.unix_path_length())
+ if maxUnixLength < len(socketPath) {
+ socketPath = socketPath[0:maxUnixLength]
+ }
+
+ logrus.Debug("connecting to socket ", socketPath)
+
+ conn, err := net.DialUnix("unixpacket", nil, &net.UnixAddr{Name: socketPath, Net: "unixpacket"})
if err != nil {
- return errors.Wrapf(err, "failed to connect to container's attach socket: %v", c.AttachSocketPath())
+ return errors.Wrapf(err, "failed to connect to container's attach socket: %v", socketPath)
}
defer conn.Close()
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index 2af216358..d928c4aed 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -5,6 +5,7 @@ import (
"context"
"encoding/json"
"fmt"
+ "github.com/opencontainers/runc/libcontainer/user"
"io"
"io/ioutil"
"os"
@@ -14,9 +15,9 @@ import (
"syscall"
"github.com/containers/buildah/imagebuildah"
- "github.com/containers/libpod/pkg/chrootuser"
"github.com/containers/libpod/pkg/hooks"
"github.com/containers/libpod/pkg/hooks/exec"
+ "github.com/containers/libpod/pkg/lookup"
"github.com/containers/libpod/pkg/resolvconf"
"github.com/containers/libpod/pkg/rootless"
"github.com/containers/libpod/pkg/secrets"
@@ -1029,7 +1030,8 @@ func (c *Container) writeStringToRundir(destFile, output string) (string, error)
func (c *Container) generatePasswd() (string, error) {
var (
groupspec string
- gid uint32
+ group *user.Group
+ gid int
)
if c.config.User == "" {
return "", nil
@@ -1044,21 +1046,27 @@ func (c *Container) generatePasswd() (string, error) {
if err != nil {
return "", nil
}
- // if UID exists inside of container rootfs /etc/passwd then
- // don't generate passwd
- if _, _, err := chrootuser.LookupUIDInContainer(c.state.Mountpoint, uid); err == nil {
+ // Lookup the user to see if it exists in the container image
+ _, err = lookup.GetUser(c.state.Mountpoint, userspec)
+ if err != nil && err != user.ErrNoPasswdEntries {
+ return "", err
+ }
+ if err == nil {
return "", nil
}
- if err == nil && groupspec != "" {
+ if groupspec != "" {
if !c.state.Mounted {
return "", errors.Wrapf(ErrCtrStateInvalid, "container %s must be mounted in order to translate group field for passwd record", c.ID())
}
- gid, err = chrootuser.GetGroup(c.state.Mountpoint, groupspec)
+ group, err = lookup.GetGroup(c.state.Mountpoint, groupspec)
if err != nil {
- return "", errors.Wrapf(err, "unable to get gid from %s formporary passwd file")
+ if err == user.ErrNoGroupEntries {
+ return "", errors.Wrapf(err, "unable to get gid %s from group file", groupspec)
+ }
+ return "", err
}
+ gid = group.Gid
}
-
originPasswdFile := filepath.Join(c.state.Mountpoint, "/etc/passwd")
orig, err := ioutil.ReadFile(originPasswdFile)
if err != nil {
@@ -1153,6 +1161,7 @@ func (c *Container) generateHosts() (string, error) {
}
func (c *Container) addLocalVolumes(ctx context.Context, g *generate.Generator) error {
+ var uid, gid int
mountPoint := c.state.Mountpoint
if !c.state.Mounted {
return errors.Wrapf(ErrInternal, "container is not mounted")
@@ -1176,6 +1185,18 @@ func (c *Container) addLocalVolumes(ctx context.Context, g *generate.Generator)
}
}
+ if c.config.User != "" {
+ if !c.state.Mounted {
+ return errors.Wrapf(ErrCtrStateInvalid, "container %s must be mounted in order to translate User field", c.ID())
+ }
+ execUser, err := lookup.GetUserGroupInfo(c.state.Mountpoint, c.config.User, nil)
+ if err != nil {
+ return err
+ }
+ uid = execUser.Uid
+ gid = execUser.Gid
+ }
+
for k := range imageData.ContainerConfig.Volumes {
mount := spec.Mount{
Destination: k,
@@ -1186,19 +1207,6 @@ func (c *Container) addLocalVolumes(ctx context.Context, g *generate.Generator)
continue
}
volumePath := filepath.Join(c.config.StaticDir, "volumes", k)
- var (
- uid uint32
- gid uint32
- )
- if c.config.User != "" {
- if !c.state.Mounted {
- return errors.Wrapf(ErrCtrStateInvalid, "container %s must be mounted in order to translate User field", c.ID())
- }
- uid, gid, err = chrootuser.GetUser(c.state.Mountpoint, c.config.User)
- if err != nil {
- return err
- }
- }
// Ensure the symlinks are resolved
resolvedSymlink, err := imagebuildah.ResolveSymLink(mountPoint, k)
@@ -1218,7 +1226,7 @@ func (c *Container) addLocalVolumes(ctx context.Context, g *generate.Generator)
return errors.Wrapf(err, "error creating directory %q for volume %q in container %q", volumePath, k, c.ID())
}
- if err = os.Chown(srcPath, int(uid), int(gid)); err != nil {
+ if err = os.Chown(srcPath, uid, gid); err != nil {
return errors.Wrapf(err, "error chowning directory %q for volume %q in container %q", srcPath, k, c.ID())
}
}
@@ -1228,7 +1236,7 @@ func (c *Container) addLocalVolumes(ctx context.Context, g *generate.Generator)
return errors.Wrapf(err, "error creating directory %q for volume %q in container %q", volumePath, k, c.ID())
}
- if err = os.Chown(volumePath, int(uid), int(gid)); err != nil {
+ if err = os.Chown(volumePath, uid, gid); err != nil {
return errors.Wrapf(err, "error chowning directory %q for volume %q in container %q", volumePath, k, c.ID())
}
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index 0a1784ba7..7bf2c71ca 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -19,12 +19,10 @@ import (
cnitypes "github.com/containernetworking/cni/pkg/types/current"
"github.com/containernetworking/plugins/pkg/ns"
crioAnnotations "github.com/containers/libpod/pkg/annotations"
- "github.com/containers/libpod/pkg/chrootuser"
"github.com/containers/libpod/pkg/criu"
+ "github.com/containers/libpod/pkg/lookup"
"github.com/containers/libpod/pkg/rootless"
"github.com/containers/storage/pkg/idtools"
- "github.com/cyphar/filepath-securejoin"
- "github.com/opencontainers/runc/libcontainer/user"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/runtime-tools/generate"
"github.com/opencontainers/selinux/go-selinux/label"
@@ -135,6 +133,10 @@ func (c *Container) cleanupNetwork() error {
// Generate spec for a container
// Accepts a map of the container's dependencies
func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
+ execUser, err := lookup.GetUserGroupInfo(c.state.Mountpoint, c.config.User, nil)
+ if err != nil {
+ return nil, err
+ }
g := generate.NewFromSpec(c.config.Spec)
// If network namespace was requested, add it now
@@ -188,7 +190,6 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
}
}
- var err error
if !rootless.IsRootless() {
if c.state.ExtensionStageHooks, err = c.setupOCIHooks(ctx, g.Config); err != nil {
return nil, errors.Wrapf(err, "error setting up OCI Hooks")
@@ -206,13 +207,9 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
if !c.state.Mounted {
return nil, errors.Wrapf(ErrCtrStateInvalid, "container %s must be mounted in order to translate User field", c.ID())
}
- uid, gid, err := chrootuser.GetUser(c.state.Mountpoint, c.config.User)
- if err != nil {
- return nil, err
- }
// User and Group must go together
- g.SetProcessUID(uid)
- g.SetProcessGID(gid)
+ g.SetProcessUID(uint32(execUser.Uid))
+ g.SetProcessGID(uint32(execUser.Gid))
}
// Add addition groups if c.config.GroupAdd is not empty
@@ -220,11 +217,8 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
if !c.state.Mounted {
return nil, errors.Wrapf(ErrCtrStateInvalid, "container %s must be mounted in order to add additional groups", c.ID())
}
- for _, group := range c.config.Groups {
- gid, err := chrootuser.GetGroup(c.state.Mountpoint, group)
- if err != nil {
- return nil, err
- }
+ gids, _ := lookup.GetContainerGroups(c.config.Groups, c.state.Mountpoint, nil)
+ for _, gid := range gids {
g.AddProcessAdditionalGid(gid)
}
}
@@ -237,26 +231,6 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
// Look up and add groups the user belongs to, if a group wasn't directly specified
if !rootless.IsRootless() && !strings.Contains(c.config.User, ":") {
- var groupDest, passwdDest string
- defaultExecUser := user.ExecUser{
- Uid: 0,
- Gid: 0,
- Home: "/",
- }
-
- // Make sure the /etc/group and /etc/passwd destinations are not a symlink to something naughty
- if groupDest, err = securejoin.SecureJoin(c.state.Mountpoint, "/etc/group"); err != nil {
- logrus.Debug(err)
- return nil, err
- }
- if passwdDest, err = securejoin.SecureJoin(c.state.Mountpoint, "/etc/passwd"); err != nil {
- logrus.Debug(err)
- return nil, err
- }
- execUser, err := user.GetExecUserPath(c.config.User, &defaultExecUser, passwdDest, groupDest)
- if err != nil {
- return nil, err
- }
for _, gid := range execUser.Sgids {
g.AddProcessAdditionalGid(uint32(gid))
}
diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go
index 0d9ec2809..863a764e2 100644
--- a/libpod/networking_linux.go
+++ b/libpod/networking_linux.go
@@ -12,6 +12,7 @@ import (
"strconv"
"strings"
"syscall"
+ "time"
cnitypes "github.com/containernetworking/cni/pkg/types/current"
"github.com/containernetworking/plugins/pkg/ns"
@@ -134,12 +135,33 @@ func (r *Runtime) setupRootlessNetNS(ctr *Container) (err error) {
cmd.ExtraFiles = append(cmd.ExtraFiles, ctr.rootlessSlirpSyncR, syncW)
if err := cmd.Start(); err != nil {
- return errors.Wrapf(err, "failed to start process")
+ return errors.Wrapf(err, "failed to start slirp4netns process")
}
+ defer cmd.Process.Release()
b := make([]byte, 16)
- if _, err := syncR.Read(b); err != nil {
- return errors.Wrapf(err, "failed to read from sync pipe")
+ for {
+ if err := syncR.SetDeadline(time.Now().Add(1 * time.Second)); err != nil {
+ return errors.Wrapf(err, "error setting slirp4netns pipe timeout")
+ }
+ if _, err := syncR.Read(b); err == nil {
+ break
+ } else {
+ if os.IsTimeout(err) {
+ // Check if the process is still running.
+ var status syscall.WaitStatus
+ _, err := syscall.Wait4(cmd.Process.Pid, &status, syscall.WNOHANG, nil)
+ if err != nil {
+ return errors.Wrapf(err, "failed to read slirp4netns process status")
+ }
+ if status.Exited() || status.Signaled() {
+ return errors.New("slirp4netns failed")
+ }
+
+ continue
+ }
+ return errors.Wrapf(err, "failed to read from slirp4netns sync pipe")
+ }
}
return nil
}
diff --git a/libpod/runtime.go b/libpod/runtime.go
index 1b26f851f..318cd0369 100644
--- a/libpod/runtime.go
+++ b/libpod/runtime.go
@@ -184,6 +184,8 @@ var (
RuntimePath: []string{
"/usr/bin/runc",
"/usr/sbin/runc",
+ "/usr/local/bin/runc",
+ "/usr/local/sbin/runc",
"/sbin/runc",
"/bin/runc",
"/usr/lib/cri-o-runc/sbin/runc",
@@ -191,6 +193,7 @@ var (
ConmonPath: []string{
"/usr/libexec/podman/conmon",
"/usr/libexec/crio/conmon",
+ "/usr/local/lib/podman/conmon",
"/usr/local/libexec/crio/conmon",
"/usr/bin/conmon",
"/usr/sbin/conmon",
@@ -206,7 +209,7 @@ var (
MaxLogSize: -1,
NoPivotRoot: false,
CNIConfigDir: "/etc/cni/net.d/",
- CNIPluginDir: []string{"/usr/libexec/cni", "/usr/lib/cni", "/opt/cni/bin"},
+ CNIPluginDir: []string{"/usr/libexec/cni", "/usr/lib/cni", "/usr/local/lib/cni", "/opt/cni/bin"},
InfraCommand: DefaultInfraCommand,
InfraImage: DefaultInfraImage,
EnablePortReservation: true,
diff --git a/pkg/lookup/lookup.go b/pkg/lookup/lookup.go
new file mode 100644
index 000000000..b27e2a724
--- /dev/null
+++ b/pkg/lookup/lookup.go
@@ -0,0 +1,156 @@
+package lookup
+
+import (
+ "github.com/cyphar/filepath-securejoin"
+ "github.com/opencontainers/runc/libcontainer/user"
+ "github.com/sirupsen/logrus"
+ "strconv"
+)
+
+const (
+ etcpasswd = "/etc/passwd"
+ etcgroup = "/etc/group"
+)
+
+// Overrides allows you to override defaults in GetUserGroupInfo
+type Overrides struct {
+ DefaultUser *user.ExecUser
+ ContainerEtcPasswdPath string
+ ContainerEtcGroupPath string
+}
+
+// GetUserGroupInfo takes string forms of the the container's mount path and the container user and
+// returns a ExecUser with uid, gid, sgids, and home. And override can be provided for defaults.
+func GetUserGroupInfo(containerMount, containerUser string, override *Overrides) (*user.ExecUser, error) {
+ var (
+ passwdDest, groupDest string
+ defaultExecUser *user.ExecUser
+ err error
+ )
+ passwdPath := etcpasswd
+ groupPath := etcgroup
+
+ if override != nil {
+ // Check for an override /etc/passwd path
+ if override.ContainerEtcPasswdPath != "" {
+ passwdPath = override.ContainerEtcPasswdPath
+ }
+ // Check for an override for /etc/group path
+ if override.ContainerEtcGroupPath != "" {
+ groupPath = override.ContainerEtcGroupPath
+ }
+ }
+
+ // Check for an override default user
+ if override != nil && override.DefaultUser != nil {
+ defaultExecUser = override.DefaultUser
+ } else {
+ // Define a default container user
+ //defaultExecUser = &user.ExecUser{
+ // Uid: 0,
+ // Gid: 0,
+ // Home: "/",
+ defaultExecUser = nil
+
+ }
+
+ // Make sure the /etc/group and /etc/passwd destinations are not a symlink to something naughty
+ if passwdDest, err = securejoin.SecureJoin(containerMount, passwdPath); err != nil {
+ logrus.Debug(err)
+ return nil, err
+ }
+ if groupDest, err = securejoin.SecureJoin(containerMount, groupPath); err != nil {
+ logrus.Debug(err)
+ return nil, err
+ }
+ return user.GetExecUserPath(containerUser, defaultExecUser, passwdDest, groupDest)
+}
+
+// GetContainerGroups uses securejoin to get a list of numerical groupids from a container. Per the runc
+// function it calls: If a group name cannot be found, an error will be returned. If a group id cannot be found,
+// or the given group data is nil, the id will be returned as-is provided it is in the legal range.
+func GetContainerGroups(groups []string, containerMount string, override *Overrides) ([]uint32, error) {
+ var (
+ groupDest string
+ err error
+ uintgids []uint32
+ )
+
+ groupPath := etcgroup
+ if override != nil && override.ContainerEtcGroupPath != "" {
+ groupPath = override.ContainerEtcGroupPath
+ }
+
+ if groupDest, err = securejoin.SecureJoin(containerMount, groupPath); err != nil {
+ logrus.Debug(err)
+ return nil, err
+ }
+
+ gids, err := user.GetAdditionalGroupsPath(groups, groupDest)
+ if err != nil {
+ return nil, err
+ }
+ // For libpod, we want []uint32s
+ for _, gid := range gids {
+ uintgids = append(uintgids, uint32(gid))
+ }
+ return uintgids, nil
+}
+
+// GetUser takes a containermount path and user name or id and returns
+// a matching User structure from /etc/passwd. If it cannot locate a user
+// with the provided information, an ErrNoPasswdEntries is returned.
+func GetUser(containerMount, userIDorName string) (*user.User, error) {
+ var inputIsName bool
+ uid, err := strconv.Atoi(userIDorName)
+ if err != nil {
+ inputIsName = true
+ }
+ passwdDest, err := securejoin.SecureJoin(containerMount, etcpasswd)
+ if err != nil {
+ return nil, err
+ }
+ users, err := user.ParsePasswdFileFilter(passwdDest, func(u user.User) bool {
+ if inputIsName {
+ return u.Name == userIDorName
+ }
+ return u.Uid == uid
+ })
+ if err != nil {
+ return nil, err
+ }
+ if len(users) > 0 {
+ return &users[0], nil
+ }
+ return nil, user.ErrNoPasswdEntries
+}
+
+// GetGroup takes ac ontainermount path and a group name or id and returns
+// a match Group struct from /etc/group. if it cannot locate a group,
+// an ErrNoGroupEntries error is returned.
+func GetGroup(containerMount, groupIDorName string) (*user.Group, error) {
+ var inputIsName bool
+ gid, err := strconv.Atoi(groupIDorName)
+ if err != nil {
+ inputIsName = true
+ }
+
+ groupDest, err := securejoin.SecureJoin(containerMount, etcgroup)
+ if err != nil {
+ return nil, err
+ }
+
+ groups, err := user.ParseGroupFileFilter(groupDest, func(g user.Group) bool {
+ if inputIsName {
+ return g.Name == groupIDorName
+ }
+ return g.Gid == gid
+ })
+ if err != nil {
+ return nil, err
+ }
+ if len(groups) > 0 {
+ return &groups[0], nil
+ }
+ return nil, user.ErrNoGroupEntries
+}