summaryrefslogtreecommitdiff
path: root/libpod
diff options
context:
space:
mode:
Diffstat (limited to 'libpod')
-rw-r--r--libpod/container_internal_linux.go41
-rw-r--r--libpod/container_log_linux.go2
-rw-r--r--libpod/image/image.go72
-rw-r--r--libpod/image/prune.go50
-rw-r--r--libpod/pod.go18
-rw-r--r--libpod/util_linux.go12
-rw-r--r--libpod/util_linux_test.go39
7 files changed, 193 insertions, 41 deletions
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index dde7cafb1..514cdaee1 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -7,6 +7,7 @@ import (
"fmt"
"io"
"io/ioutil"
+ "math"
"net"
"os"
"os/user"
@@ -35,6 +36,7 @@ import (
"github.com/containers/podman/v2/pkg/util"
"github.com/containers/podman/v2/utils"
"github.com/containers/storage/pkg/archive"
+ "github.com/containers/storage/pkg/idtools"
securejoin "github.com/cyphar/filepath-securejoin"
runcuser "github.com/opencontainers/runc/libcontainer/user"
spec "github.com/opencontainers/runtime-spec/specs-go"
@@ -415,9 +417,44 @@ 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, ":") {
+ if !strings.Contains(c.config.User, ":") {
+ // the gidMappings that are present inside the container user namespace
+ var gidMappings []idtools.IDMap
+
+ switch {
+ case len(c.config.IDMappings.GIDMap) > 0:
+ gidMappings = c.config.IDMappings.GIDMap
+ case rootless.IsRootless():
+ // Check whether the current user namespace has enough gids available.
+ availableGids, err := rootless.GetAvailableGids()
+ if err != nil {
+ return nil, errors.Wrapf(err, "cannot read number of available GIDs")
+ }
+ gidMappings = []idtools.IDMap{{
+ ContainerID: 0,
+ HostID: 0,
+ Size: int(availableGids),
+ }}
+ default:
+ gidMappings = []idtools.IDMap{{
+ ContainerID: 0,
+ HostID: 0,
+ Size: math.MaxInt32,
+ }}
+ }
for _, gid := range execUser.Sgids {
- g.AddProcessAdditionalGid(uint32(gid))
+ isGidAvailable := false
+ for _, m := range gidMappings {
+ if gid >= m.ContainerID && gid < m.ContainerID+m.Size {
+ isGidAvailable = true
+ break
+ }
+ }
+ if isGidAvailable {
+ g.AddProcessAdditionalGid(uint32(gid))
+ } else {
+ logrus.Warnf("additional gid=%d is not present in the user namespace, skip setting it", gid)
+ }
}
}
diff --git a/libpod/container_log_linux.go b/libpod/container_log_linux.go
index 73c2df76e..d895171cf 100644
--- a/libpod/container_log_linux.go
+++ b/libpod/container_log_linux.go
@@ -33,7 +33,7 @@ const (
func (c *Container) readFromJournal(ctx context.Context, options *logs.LogOptions, logChannel chan *logs.LogLine) error {
var config journal.JournalReaderConfig
if options.Tail < 0 {
- config.NumFromTail = math.MaxUint64
+ config.NumFromTail = 0
} else {
config.NumFromTail = uint64(options.Tail)
}
diff --git a/libpod/image/image.go b/libpod/image/image.go
index 5dfb33afb..f5bf47694 100644
--- a/libpod/image/image.go
+++ b/libpod/image/image.go
@@ -410,48 +410,92 @@ func (ir *Runtime) getLocalImage(inputName string) (string, *storage.Image, erro
if inputName == "" {
return "", nil, errors.Errorf("input name is blank")
}
+
// Check if the input name has a transport and if so strip it
dest, err := alltransports.ParseImageName(inputName)
if err == nil && dest.DockerReference() != nil {
inputName = dest.DockerReference().String()
}
- img, err := ir.getImage(stripSha256(inputName))
+ // Early check for fully-qualified images and (short) IDs.
+ img, err := ir.store.Image(stripSha256(inputName))
if err == nil {
- return inputName, img, err
+ return inputName, img, nil
}
- // container-storage wasn't able to find it in its current form
- // check if the input name has a tag, and if not, run it through
- // again
+ // Note that it's crucial to first decompose the image and check if
+ // it's a fully-qualified one or a "short name". The latter requires
+ // some normalization with search registries and the
+ // "localhost/prefix".
decomposedImage, err := decompose(inputName)
if err != nil {
+ // We may have a storage reference. We can't parse it to a
+ // reference before. Otherwise, we'd normalize "alpine" to
+ // "docker.io/library/alpine:latest" which would break the
+ // order in which we should query local images below.
+ if ref, err := is.Transport.ParseStoreReference(ir.store, inputName); err == nil {
+ img, err = is.Transport.GetStoreImage(ir.store, ref)
+ if err == nil {
+ return inputName, img, nil
+ }
+ }
return "", nil, err
}
- // The image has a registry name in it and we made sure we looked for it locally
- // with a tag. It cannot be local.
+ // The specified image is fully qualified, so it doesn't exist in the
+ // storage.
if decomposedImage.hasRegistry {
+ // However ... we may still need to normalize to docker.io:
+ // `docker.io/foo` -> `docker.io/library/foo`
+ if ref, err := is.Transport.ParseStoreReference(ir.store, inputName); err == nil {
+ img, err = is.Transport.GetStoreImage(ir.store, ref)
+ if err == nil {
+ return inputName, img, nil
+ }
+ }
return "", nil, errors.Wrapf(ErrNoSuchImage, imageError)
}
- // if the image is saved with the repository localhost, searching with localhost prepended is necessary
- // We don't need to strip the sha because we have already determined it is not an ID
- ref, err := decomposedImage.referenceWithRegistry(DefaultLocalRegistry)
+
+ // "Short-name image", so let's try out certain prefixes:
+ // 1) DefaultLocalRegistry (i.e., "localhost/)
+ // 2) Unqualified-search registries from registries.conf
+ unqualifiedSearchRegistries, err := registries.GetRegistries()
if err != nil {
return "", nil, err
}
- img, err = ir.getImage(ref.String())
+
+ for _, candidate := range append([]string{DefaultLocalRegistry}, unqualifiedSearchRegistries...) {
+ ref, err := decomposedImage.referenceWithRegistry(candidate)
+ if err != nil {
+ return "", nil, err
+ }
+ img, err := ir.store.Image(ref.String())
+ if err == nil {
+ return ref.String(), img, nil
+ }
+ }
+
+ // Backwards compat: normalize to docker.io as some users may very well
+ // rely on that.
+ ref, err := is.Transport.ParseStoreReference(ir.store, inputName)
if err == nil {
- return inputName, img, err
+ img, err = is.Transport.GetStoreImage(ir.store, ref)
+ if err == nil {
+ return inputName, img, nil
+ }
}
- // grab all the local images
+ // Last resort: look at the repotags of all images and try to find a
+ // match.
images, err := ir.GetImages()
if err != nil {
return "", nil, err
}
- // check the repotags of all images for a match
+ decomposedImage, err = decompose(inputName)
+ if err != nil {
+ return "", nil, err
+ }
repoImage, err := findImageInRepotags(decomposedImage, images)
if err == nil {
return inputName, repoImage, nil
diff --git a/libpod/image/prune.go b/libpod/image/prune.go
index fcc65fb03..b38265a7e 100644
--- a/libpod/image/prune.go
+++ b/libpod/image/prune.go
@@ -125,29 +125,39 @@ func (ir *Runtime) PruneImages(ctx context.Context, all bool, filter []string) (
filterFuncs = append(filterFuncs, generatedFunc)
}
- pruneImages, err := ir.GetPruneImages(ctx, all, filterFuncs)
- if err != nil {
- return nil, errors.Wrap(err, "unable to get images to prune")
- }
- prunedCids := make([]string, 0, len(pruneImages))
- for _, p := range pruneImages {
- repotags, err := p.RepoTags()
+ pruned := []string{}
+ prev := 0
+ for {
+ toPrune, err := ir.GetPruneImages(ctx, all, filterFuncs)
if err != nil {
- return nil, err
+ return nil, errors.Wrap(err, "unable to get images to prune")
}
- if err := p.Remove(ctx, true); err != nil {
- if errors.Cause(err) == storage.ErrImageUsedByContainer {
- logrus.Warnf("Failed to prune image %s as it is in use: %v.\nA container associated with containers/storage i.e. Buildah, CRI-O, etc., maybe associated with this image.\nUsing the rmi command with the --force option will remove the container and image, but may cause failures for other dependent systems.", p.ID(), err)
- continue
- }
- return nil, errors.Wrap(err, "failed to prune image")
+ numImages := len(toPrune)
+ if numImages == 0 || numImages == prev {
+ // If there's nothing left to do, return.
+ break
}
- defer p.newImageEvent(events.Prune)
- nameOrID := p.ID()
- if len(repotags) > 0 {
- nameOrID = repotags[0]
+ prev = numImages
+ for _, img := range toPrune {
+ repotags, err := img.RepoTags()
+ if err != nil {
+ return nil, err
+ }
+ if err := img.Remove(ctx, false); err != nil {
+ if errors.Cause(err) == storage.ErrImageUsedByContainer {
+ logrus.Warnf("Failed to prune image %s as it is in use: %v.\nA container associated with containers/storage (e.g., Buildah, CRI-O, etc.) maybe associated with this image.\nUsing the rmi command with the --force option will remove the container and image, but may cause failures for other dependent systems.", img.ID(), err)
+ continue
+ }
+ return nil, errors.Wrap(err, "failed to prune image")
+ }
+ defer img.newImageEvent(events.Prune)
+ nameOrID := img.ID()
+ if len(repotags) > 0 {
+ nameOrID = repotags[0]
+ }
+ pruned = append(pruned, nameOrID)
}
- prunedCids = append(prunedCids, nameOrID)
+
}
- return prunedCids, nil
+ return pruned, nil
}
diff --git a/libpod/pod.go b/libpod/pod.go
index a5a0532be..c8f62ca18 100644
--- a/libpod/pod.go
+++ b/libpod/pod.go
@@ -327,3 +327,21 @@ func (p *Pod) GetPodStats(previousContainerStats map[string]*define.ContainerSta
}
return newContainerStats, nil
}
+
+// ProcessLabel returns the SELinux label associated with the pod
+func (p *Pod) ProcessLabel() (string, error) {
+ if !p.HasInfraContainer() {
+ return "", nil
+ }
+
+ id, err := p.InfraContainerID()
+ if err != nil {
+ return "", err
+ }
+
+ ctr, err := p.runtime.state.Container(id)
+ if err != nil {
+ return "", err
+ }
+ return ctr.ProcessLabel(), nil
+}
diff --git a/libpod/util_linux.go b/libpod/util_linux.go
index 03c3ab061..5184ed393 100644
--- a/libpod/util_linux.go
+++ b/libpod/util_linux.go
@@ -90,19 +90,23 @@ func assembleSystemdCgroupName(baseSlice, newSlice string) (string, error) {
return final, nil
}
+var lvpRelabel = label.Relabel
+var lvpInitLabels = label.InitLabels
+var lvpReleaseLabel = label.ReleaseLabel
+
// LabelVolumePath takes a mount path for a volume and gives it an
// selinux label of either shared or not
func LabelVolumePath(path string) error {
- _, mountLabel, err := label.InitLabels([]string{})
+ _, mountLabel, err := lvpInitLabels([]string{})
if err != nil {
return errors.Wrapf(err, "error getting default mountlabels")
}
- if err := label.ReleaseLabel(mountLabel); err != nil {
+ if err := lvpReleaseLabel(mountLabel); err != nil {
return errors.Wrapf(err, "error releasing label %q", mountLabel)
}
- if err := label.Relabel(path, mountLabel, true); err != nil {
- if err != syscall.ENOTSUP {
+ if err := lvpRelabel(path, mountLabel, true); err != nil {
+ if err == syscall.ENOTSUP {
logrus.Debugf("Labeling not supported on %q", path)
} else {
return errors.Wrapf(err, "error setting selinux label for %s to %q as shared", path, mountLabel)
diff --git a/libpod/util_linux_test.go b/libpod/util_linux_test.go
new file mode 100644
index 000000000..5fcb04beb
--- /dev/null
+++ b/libpod/util_linux_test.go
@@ -0,0 +1,39 @@
+package libpod
+
+import (
+ "syscall"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestLabelVolumePath(t *testing.T) {
+ // Set up mocked SELinux functions for testing.
+ oldRelabel := lvpRelabel
+ oldInitLabels := lvpInitLabels
+ oldReleaseLabel := lvpReleaseLabel
+ defer func() {
+ lvpRelabel = oldRelabel
+ lvpInitLabels = oldInitLabels
+ lvpReleaseLabel = oldReleaseLabel
+ }()
+
+ // Relabel returns ENOTSUP unconditionally.
+ lvpRelabel = func(path string, fileLabel string, shared bool) error {
+ return syscall.ENOTSUP
+ }
+
+ // InitLabels and ReleaseLabel both return dummy values and nil errors.
+ lvpInitLabels = func(options []string) (string, string, error) {
+ pLabel := "system_u:system_r:container_t:s0:c1,c2"
+ mLabel := "system_u:object_r:container_file_t:s0:c1,c2"
+ return pLabel, mLabel, nil
+ }
+ lvpReleaseLabel = func(label string) error {
+ return nil
+ }
+
+ // LabelVolumePath should not return an error if the operation is unsupported.
+ err := LabelVolumePath("/foo/bar")
+ assert.NoError(t, err)
+}