diff --git a/go.mod b/go.mod index d54c3589..6cc9413a 100644 --- a/go.mod +++ b/go.mod @@ -3,9 +3,9 @@ module github.com/containers/prometheus-podman-exporter go 1.21.0 require ( - github.com/containers/common v0.60.2 + github.com/containers/common v0.60.3 github.com/containers/image/v5 v5.32.2 - github.com/containers/podman/v5 v5.2.2 + github.com/containers/podman/v5 v5.2.3 github.com/go-kit/log v0.2.1 github.com/onsi/ginkgo/v2 v2.20.1 github.com/onsi/gomega v1.34.1 @@ -41,7 +41,7 @@ require ( github.com/containerd/typeurl/v2 v2.1.1 // indirect github.com/containernetworking/cni v1.2.3 // indirect github.com/containernetworking/plugins v1.5.1 // indirect - github.com/containers/buildah v1.37.2 // indirect + github.com/containers/buildah v1.37.3 // indirect github.com/containers/conmon v2.0.20+incompatible // indirect github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 // indirect github.com/containers/luksy v0.0.0-20240618143119-a8846e21c08c // indirect @@ -116,7 +116,7 @@ require ( github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/mountinfo v0.7.2 // indirect github.com/moby/sys/sequential v0.5.0 // indirect - github.com/moby/sys/user v0.2.0 // indirect + github.com/moby/sys/user v0.3.0 // indirect github.com/moby/term v0.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect diff --git a/go.sum b/go.sum index 0522aee2..08367642 100644 --- a/go.sum +++ b/go.sum @@ -62,10 +62,10 @@ github.com/containernetworking/cni v1.2.3 h1:hhOcjNVUQTnzdRJ6alC5XF+wd9mfGIUaj8F github.com/containernetworking/cni v1.2.3/go.mod h1:DuLgF+aPd3DzcTQTtp/Nvl1Kim23oFKdm2okJzBQA5M= github.com/containernetworking/plugins v1.5.1 h1:T5ji+LPYjjgW0QM+KyrigZbLsZ8jaX+E5J/EcKOE4gQ= github.com/containernetworking/plugins v1.5.1/go.mod h1:MIQfgMayGuHYs0XdNudf31cLLAC+i242hNm6KuDGqCM= -github.com/containers/buildah v1.37.2 h1:KiJ3jVNUvdtGORxDz8fjjLkR81ZHQZIfnGWJWavks40= -github.com/containers/buildah v1.37.2/go.mod h1:alFCM3X0xfhE6ZjsFQkUlOMyKzOnbv9FL9fe1Ho48PA= -github.com/containers/common v0.60.2 h1:utcwp2YkO8c0mNlwRxsxfOiqfj157FRrBjxgjR6f+7o= -github.com/containers/common v0.60.2/go.mod h1:I0upBi1qJX3QmzGbUOBN1LVP6RvkKhd3qQpZbQT+Q54= +github.com/containers/buildah v1.37.3 h1:nSmbdBqaRMjvTtwVuOKZGT2jefaUKsZXbgpH9b4HzIs= +github.com/containers/buildah v1.37.3/go.mod h1:alFCM3X0xfhE6ZjsFQkUlOMyKzOnbv9FL9fe1Ho48PA= +github.com/containers/common v0.60.3 h1:pToT7gtFx/KWyMtWw98g4pIbW54i9KfGH2QrdN2s1io= +github.com/containers/common v0.60.3/go.mod h1:I0upBi1qJX3QmzGbUOBN1LVP6RvkKhd3qQpZbQT+Q54= github.com/containers/conmon v2.0.20+incompatible h1:YbCVSFSCqFjjVwHTPINGdMX1F6JXHGTUje2ZYobNrkg= github.com/containers/conmon v2.0.20+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I= github.com/containers/image/v5 v5.32.2 h1:SzNE2Y6sf9b1GJoC8qjCuMBXwQrACFp4p0RK15+4gmQ= @@ -76,8 +76,8 @@ github.com/containers/luksy v0.0.0-20240618143119-a8846e21c08c h1:gJDiBJYc8JFD46 github.com/containers/luksy v0.0.0-20240618143119-a8846e21c08c/go.mod h1:Ufusu7xAtl0LSTry0JS6dSxbxR/XJQSEqlhLqTkCaH8= github.com/containers/ocicrypt v1.2.0 h1:X14EgRK3xNFvJEfI5O4Qn4T3E25ANudSOZz/sirVuPM= github.com/containers/ocicrypt v1.2.0/go.mod h1:ZNviigQajtdlxIZGibvblVuIFBKIuUI2M0QM12SD31U= -github.com/containers/podman/v5 v5.2.2 h1:UHDF+CeuRgqQc4EN0MNXrk1Xb45/5td/ClGmAOyiDJ8= -github.com/containers/podman/v5 v5.2.2/go.mod h1:6RoRmwWUDYzAdDMJnzBWiSxGJF7xJinJG+s4RnczwZw= +github.com/containers/podman/v5 v5.2.3 h1:jDAfDHoNqYsQMsKQS/8fnjfp+ZEErxOb4zzJGXUcZCQ= +github.com/containers/podman/v5 v5.2.3/go.mod h1:LnDGMLgJdMWzWpsvrmXDzR8iZ4kZE6p0CFZdQbfAoBI= github.com/containers/psgo v1.9.0 h1:eJ74jzSaCHnWt26OlKZROSyUyRcGDf+gYBdXnxrMW4g= github.com/containers/psgo v1.9.0/go.mod h1:0YoluUm43Mz2UnBIh1P+6V6NWcbpTL5uRtXyOcH0B5A= github.com/containers/storage v1.55.0 h1:wTWZ3YpcQf1F+dSP4KxG9iqDfpQY1otaUXjPpffuhgg= @@ -275,8 +275,8 @@ github.com/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9Kou github.com/moby/sys/mountinfo v0.7.2/go.mod h1:1YOa8w8Ih7uW0wALDUgT1dTTSBrZ+HiBLGws92L2RU4= github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc= github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= -github.com/moby/sys/user v0.2.0 h1:OnpapJsRp25vkhw8TFG6OLJODNh/3rEwRWtJ3kakwRM= -github.com/moby/sys/user v0.2.0/go.mod h1:RYstrcWOJpVh+6qzUqp2bU3eaRpdiQeKGlKitaH0PM8= +github.com/moby/sys/user v0.3.0 h1:9ni5DlcW5an3SvRSx4MouotOygvzaXbaSrc/wGDFWPo= +github.com/moby/sys/user v0.3.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs= github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= diff --git a/vendor/github.com/containers/buildah/.packit.yaml b/vendor/github.com/containers/buildah/.packit.yaml index b465fec6..b96a1605 100644 --- a/vendor/github.com/containers/buildah/.packit.yaml +++ b/vendor/github.com/containers/buildah/.packit.yaml @@ -14,6 +14,8 @@ packages: specfile_path: rpm/buildah.spec buildah-rhel: specfile_path: rpm/buildah.spec + buildah-eln: + specfile_path: rpm/buildah.spec srpm_build_deps: - make @@ -26,8 +28,21 @@ jobs: failure_comment: message: "Ephemeral COPR build failed. @containers/packit-build please check." targets: - fedora-all-x86_64: {} - fedora-all-aarch64: {} + - fedora-development-x86_64 + - fedora-development-aarch64 + - fedora-latest-x86_64 + - fedora-latest-aarch64 + - fedora-latest-stable-x86_64 + - fedora-latest-stable-aarch64 + - fedora-40-x86_64 + - fedora-40-aarch64 + enable_net: true + + - job: copr_build + trigger: pull_request + packages: [buildah-eln] + notifications: *copr_build_failure_notification + targets: fedora-eln-x86_64: additional_repos: - "https://kojipkgs.fedoraproject.org/repos/eln-build/latest/x86_64/" @@ -73,7 +88,7 @@ jobs: trigger: release packages: [buildah-fedora] update_release: false - dist_git_branches: + dist_git_branches: &fedora_targets - fedora-all # Sync to CentOS Stream @@ -84,12 +99,13 @@ jobs: dist_git_branches: - c10s + # Fedora Koji build - job: koji_build trigger: commit - dist_git_branches: - - fedora-all - - - job: bodhi_update - trigger: commit - dist_git_branches: - - fedora-branched # rawhide updates are created automatically + sidetag_group: podman-releases + # Dependents are not rpm dependencies, but the package whose bodhi update + # should include this package. + # Ref: https://packit.dev/docs/fedora-releases-guide/releasing-multiple-packages + dependents: + - podman + dist_git_branches: *fedora_targets diff --git a/vendor/github.com/containers/buildah/CHANGELOG.md b/vendor/github.com/containers/buildah/CHANGELOG.md index 8434e6ae..bbe234f0 100644 --- a/vendor/github.com/containers/buildah/CHANGELOG.md +++ b/vendor/github.com/containers/buildah/CHANGELOG.md @@ -2,6 +2,15 @@ # Changelog +## v1.37.3 (2024-09-20) + + Do not error on trying to write IMA xattr as rootless + imagebuildah.StageExecutor: clean up volumes/volumeCache + `manifest add --artifact`: handle multiple values + Packit: split out ELN jobs and reuse fedora downstream targets + Packit: Enable sidetags for bodhi updates + Use Epoch: 2 and respect the epoch in dependencies. + ## v1.37.2 (2024-08-20) [release-1.37] Bump c/common to v0.60.2, c/image to v5.32.2 diff --git a/vendor/github.com/containers/buildah/changelog.txt b/vendor/github.com/containers/buildah/changelog.txt index 0d3b0122..50a226da 100644 --- a/vendor/github.com/containers/buildah/changelog.txt +++ b/vendor/github.com/containers/buildah/changelog.txt @@ -1,3 +1,11 @@ +- Changelog for v1.37.3 (2024-09-20) + * Do not error on trying to write IMA xattr as rootless + * imagebuildah.StageExecutor: clean up volumes/volumeCache + * `manifest add --artifact`: handle multiple values + * Packit: split out ELN jobs and reuse fedora downstream targets + * Packit: Enable sidetags for bodhi updates + * Use Epoch: 2 and respect the epoch in dependencies. + - Changelog for v1.37.2 (2024-08-20) * [release-1.37] Bump c/common to v0.60.2, c/image to v5.32.2 diff --git a/vendor/github.com/containers/buildah/copier/xattrs.go b/vendor/github.com/containers/buildah/copier/xattrs.go index f5b2e731..c0d93ac1 100644 --- a/vendor/github.com/containers/buildah/copier/xattrs.go +++ b/vendor/github.com/containers/buildah/copier/xattrs.go @@ -10,15 +10,18 @@ import ( "strings" "syscall" + "github.com/containers/storage/pkg/unshare" + "github.com/sirupsen/logrus" "golang.org/x/sys/unix" ) const ( xattrsSupported = true + imaXattr = "security.ima" ) var ( - relevantAttributes = []string{"security.capability", "security.ima", "user.*"} // the attributes that we preserve - we discard others + relevantAttributes = []string{"security.capability", imaXattr, "user.*"} // the attributes that we preserve - we discard others initialXattrListSize = 64 * 1024 initialXattrValueSize = 64 * 1024 ) @@ -93,7 +96,11 @@ func Lsetxattrs(path string, xattrs map[string]string) error { for attribute, value := range xattrs { if isRelevantXattr(attribute) { if err := unix.Lsetxattr(path, attribute, []byte(value), 0); err != nil { - return fmt.Errorf("setting value of extended attribute %q on %q: %w", attribute, path, err) + if unshare.IsRootless() && attribute == imaXattr { + logrus.Warnf("Unable to set %q xattr on %q: %v", attribute, path, err) + } else { + return fmt.Errorf("setting value of extended attribute %q on %q: %w", attribute, path, err) + } } } } diff --git a/vendor/github.com/containers/buildah/define/types.go b/vendor/github.com/containers/buildah/define/types.go index 8e2615eb..0fd7b5d9 100644 --- a/vendor/github.com/containers/buildah/define/types.go +++ b/vendor/github.com/containers/buildah/define/types.go @@ -29,7 +29,7 @@ const ( // identify working containers. Package = "buildah" // Version for the Package. Also used by .packit.sh for Packit builds. - Version = "1.37.2" + Version = "1.37.3" // DefaultRuntime if containers.conf fails. DefaultRuntime = "runc" diff --git a/vendor/github.com/containers/buildah/imagebuildah/build.go b/vendor/github.com/containers/buildah/imagebuildah/build.go index ca737475..9dc5d7bf 100644 --- a/vendor/github.com/containers/buildah/imagebuildah/build.go +++ b/vendor/github.com/containers/buildah/imagebuildah/build.go @@ -143,7 +143,7 @@ func BuildDockerfiles(ctx context.Context, store storage.Store, options define.B } contents, err = os.Open(dfile) if err != nil { - return "", nil, err + return "", nil, fmt.Errorf("reading build instructions: %w", err) } dinfo, err = contents.Stat() if err != nil { diff --git a/vendor/github.com/containers/buildah/imagebuildah/executor.go b/vendor/github.com/containers/buildah/imagebuildah/executor.go index 6579fd17..0fcc66ac 100644 --- a/vendor/github.com/containers/buildah/imagebuildah/executor.go +++ b/vendor/github.com/containers/buildah/imagebuildah/executor.go @@ -222,7 +222,7 @@ func newExecutor(logger *logrus.Logger, logPrefix string, store storage.Store, o } else { rusageLogFile, err = os.OpenFile(options.RusageLogFile, os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0644) if err != nil { - return nil, err + return nil, fmt.Errorf("creating file to store rusage logs: %w", err) } } } diff --git a/vendor/github.com/containers/buildah/imagebuildah/stage_executor.go b/vendor/github.com/containers/buildah/imagebuildah/stage_executor.go index b8a01bef..34e836ad 100644 --- a/vendor/github.com/containers/buildah/imagebuildah/stage_executor.go +++ b/vendor/github.com/containers/buildah/imagebuildah/stage_executor.go @@ -67,9 +67,9 @@ type StageExecutor struct { name string builder *buildah.Builder preserved int - volumes imagebuilder.VolumeSet - volumeCache map[string]string - volumeCacheInfo map[string]os.FileInfo + volumes imagebuilder.VolumeSet // list of directories which are volumes + volumeCache map[string]string // mapping from volume directories to cache archives (used by vfs method) + volumeCacheInfo map[string]os.FileInfo // mapping from volume directories to perms/datestamps to reset after restoring mountPoint string output string containerIDs []string @@ -92,7 +92,7 @@ type StageExecutor struct { // writeable while the RUN instruction is being handled, even if any changes // made within the directory are ultimately discarded. func (s *StageExecutor) Preserve(path string) error { - logrus.Debugf("PRESERVE %q in %q", path, s.builder.ContainerID) + logrus.Debugf("PRESERVE %q in %q (already preserving %v)", path, s.builder.ContainerID, s.volumes) // Try and resolve the symlink (if one exists) // Set archivedPath and path based on whether a symlink is found or not @@ -111,71 +111,61 @@ func (s *StageExecutor) Preserve(path string) error { return fmt.Errorf("evaluating path %q: %w", path, err) } + // Whether or not we're caching and restoring the contents of this + // directory, we need to ensure it exists now. const createdDirPerms = os.FileMode(0o755) - if s.executor.compatVolumes != types.OptionalBoolTrue { - logrus.Debugf("ensuring volume path %q exists", path) + st, err := os.Stat(archivedPath) + if errors.Is(err, os.ErrNotExist) { + // Yup, we do have to create it. That means it's not in any + // cached copy of the path that covers it, so we have to + // invalidate such cached copy. + logrus.Debugf("have to create volume %q", path) createdDirPerms := createdDirPerms if err := copier.Mkdir(s.mountPoint, archivedPath, copier.MkdirOptions{ChmodNew: &createdDirPerms}); err != nil { return fmt.Errorf("ensuring volume path exists: %w", err) } - logrus.Debugf("not doing volume save-and-restore of %q in %q", path, s.builder.ContainerID) - return nil + if err := s.volumeCacheInvalidate(path); err != nil { + return fmt.Errorf("ensuring volume path %q is preserved: %w", filepath.Join(s.mountPoint, path), err) + } + if st, err = os.Stat(archivedPath); err != nil { + return fmt.Errorf("checking on just-created volume path: %w", err) + } + } + if err != nil { + return fmt.Errorf("reading info cache for volume at %q: %w", path, err) } if s.volumes.Covers(path) { // This path is a subdirectory of a volume path that we're - // already preserving, so there's nothing new to be done except - // ensure that it exists. - st, err := os.Stat(archivedPath) - if errors.Is(err, os.ErrNotExist) { - // We do have to create it. That means it's not in any - // cached copy of the path that covers it, so we have - // to invalidate such cached copy. - logrus.Debugf("have to create volume %q", path) - createdDirPerms := createdDirPerms - if err := copier.Mkdir(s.mountPoint, filepath.Join(s.mountPoint, path), copier.MkdirOptions{ChmodNew: &createdDirPerms}); err != nil { - return fmt.Errorf("ensuring volume path exists: %w", err) - } - if err := s.volumeCacheInvalidate(path); err != nil { - return fmt.Errorf("ensuring volume path %q is preserved: %w", filepath.Join(s.mountPoint, path), err) - } - if st, err = os.Stat(archivedPath); err != nil { - return fmt.Errorf("checking on just-created volume path: %w", err) - } - } + // already preserving, so there's nothing new to be done now + // that we've ensured that it exists. s.volumeCacheInfo[path] = st return nil } - // Figure out where the cache for this volume would be stored. - s.preserved++ - cacheDir, err := s.executor.store.ContainerDirectory(s.builder.ContainerID) - if err != nil { - return fmt.Errorf("unable to locate temporary directory for container") - } - cacheFile := filepath.Join(cacheDir, fmt.Sprintf("volume%d.tar", s.preserved)) - - // Save info about the top level of the location that we'll be archiving. - st, err := os.Stat(archivedPath) - if errors.Is(err, os.ErrNotExist) { - logrus.Debugf("have to create volume %q", path) - createdDirPerms := os.FileMode(0o755) - if err = copier.Mkdir(s.mountPoint, archivedPath, copier.MkdirOptions{ChmodNew: &createdDirPerms}); err != nil { - return fmt.Errorf("ensuring volume path exists: %w", err) - } - st, err = os.Stat(archivedPath) - } - if err != nil { - logrus.Debugf("error reading info about %q: %v", archivedPath, err) - return err - } - s.volumeCacheInfo[path] = st + // Add the new volume path to the ones that we're tracking. if !s.volumes.Add(path) { // This path is not a subdirectory of a volume path that we're // already preserving, so adding it to the list should have // worked. return fmt.Errorf("adding %q to the volume cache", path) } + s.volumeCacheInfo[path] = st + + // If we're not doing save/restore, we're done, since volumeCache + // should be empty. + if s.executor.compatVolumes != types.OptionalBoolTrue { + logrus.Debugf("not doing volume save-and-restore of %q in %q", path, s.builder.ContainerID) + return nil + } + + // Decide where the cache for this volume will be stored. + s.preserved++ + cacheDir, err := s.executor.store.ContainerDirectory(s.builder.ContainerID) + if err != nil { + return fmt.Errorf("unable to locate temporary directory for container") + } + cacheFile := filepath.Join(cacheDir, fmt.Sprintf("volume%d.tar", s.preserved)) s.volumeCache[path] = cacheFile // Now prune cache files for volumes that are newly supplanted by this one. @@ -206,7 +196,7 @@ func (s *StageExecutor) Preserve(path string) error { if errors.Is(err, os.ErrNotExist) { continue } - return err + return fmt.Errorf("removing cache of %q: %w", archivedPath, err) } delete(s.volumeCache, cachedPath) } @@ -256,16 +246,12 @@ func (s *StageExecutor) volumeCacheSaveVFS() (mounts []specs.Mount, err error) { continue } if !errors.Is(err, os.ErrNotExist) { - return nil, err - } - createdDirPerms := os.FileMode(0755) - if err := copier.Mkdir(s.mountPoint, archivedPath, copier.MkdirOptions{ChmodNew: &createdDirPerms}); err != nil { - return nil, fmt.Errorf("ensuring volume path exists: %w", err) + return nil, fmt.Errorf("checking for presence of a cached copy of %q at %q: %w", cachedPath, cacheFile, err) } logrus.Debugf("caching contents of volume %q in %q", archivedPath, cacheFile) cache, err := os.Create(cacheFile) if err != nil { - return nil, err + return nil, fmt.Errorf("creating cache for volume %q: %w", archivedPath, err) } defer cache.Close() rc, err := chrootarchive.Tar(archivedPath, nil, s.mountPoint) @@ -298,16 +284,12 @@ func (s *StageExecutor) volumeCacheRestoreVFS() (err error) { logrus.Debugf("restoring contents of volume %q from %q", archivedPath, cacheFile) cache, err := os.Open(cacheFile) if err != nil { - return err + return fmt.Errorf("restoring contents of volume %q: %w", archivedPath, err) } defer cache.Close() if err := copier.Remove(s.mountPoint, archivedPath, copier.RemoveOptions{All: true}); err != nil { return err } - createdDirPerms := os.FileMode(0o755) - if err := copier.Mkdir(s.mountPoint, archivedPath, copier.MkdirOptions{ChmodNew: &createdDirPerms}); err != nil { - return err - } err = chrootarchive.Untar(cache, archivedPath, nil) if err != nil { return fmt.Errorf("extracting archive at %q: %w", archivedPath, err) @@ -334,13 +316,11 @@ func (s *StageExecutor) volumeCacheRestoreVFS() (err error) { } // Save the contents of each of the executor's list of volumes for which we -// don't already have a cache file. +// don't already have a cache file. For overlay, we "save" and "restore" by +// using it as a lower for an overlay mount in the same location, and then +// discarding the upper. func (s *StageExecutor) volumeCacheSaveOverlay() (mounts []specs.Mount, err error) { for cachedPath := range s.volumeCache { - err = copier.Mkdir(s.mountPoint, filepath.Join(s.mountPoint, cachedPath), copier.MkdirOptions{}) - if err != nil { - return nil, fmt.Errorf("ensuring volume exists: %w", err) - } volumePath := filepath.Join(s.mountPoint, cachedPath) mount := specs.Mount{ Source: volumePath, @@ -1079,6 +1059,7 @@ func (s *StageExecutor) prepare(ctx context.Context, from string, initializeIBCo s.mountPoint = mountPoint s.builder = builder // Now that the rootfs is mounted, set up handling of volumes from the base image. + s.volumes = make([]string, 0, len(s.volumes)) s.volumeCache = make(map[string]string) s.volumeCacheInfo = make(map[string]os.FileInfo) for _, v := range builder.Volumes() { diff --git a/vendor/github.com/containers/common/pkg/netns/netns_linux.go b/vendor/github.com/containers/common/pkg/netns/netns_linux.go index bbcedc0f..3a337288 100644 --- a/vendor/github.com/containers/common/pkg/netns/netns_linux.go +++ b/vendor/github.com/containers/common/pkg/netns/netns_linux.go @@ -40,6 +40,8 @@ import ( // threadNsPath is the /proc path to the current netns handle for the current thread const threadNsPath = "/proc/thread-self/ns/net" +var errNoFreeName = errors.New("failed to find free netns path name") + // GetNSRunDir returns the dir of where to create the netNS. When running // rootless, it needs to be at a location writable by user. func GetNSRunDir() (string, error) { @@ -60,14 +62,26 @@ func NewNSAtPath(nsPath string) (ns.NetNS, error) { // NewNS creates a new persistent (bind-mounted) network namespace and returns // an object representing that namespace, without switching to it. func NewNS() (ns.NetNS, error) { + nsRunDir, err := GetNSRunDir() + if err != nil { + return nil, err + } + + // Create the directory for mounting network namespaces + // This needs to be a shared mountpoint in case it is mounted in to + // other namespaces (containers) + err = makeNetnsDir(nsRunDir) + if err != nil { + return nil, err + } + for i := 0; i < 10000; i++ { - b := make([]byte, 16) - _, err := rand.Reader.Read(b) + nsName, err := getRandomNetnsName() if err != nil { - return nil, fmt.Errorf("failed to generate random netns name: %v", err) + return nil, err } - nsName := fmt.Sprintf("netns-%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:]) - ns, err := NewNSWithName(nsName) + nsPath := path.Join(nsRunDir, nsName) + ns, err := newNSPath(nsPath) if err == nil { return ns, nil } @@ -77,62 +91,128 @@ func NewNS() (ns.NetNS, error) { } return nil, err } - return nil, errors.New("failed to find free netns path name") + return nil, errNoFreeName } -// NewNSWithName creates a new persistent (bind-mounted) network namespace and returns -// an object representing that namespace, without switching to it. -func NewNSWithName(name string) (ns.NetNS, error) { +// NewNSFrom creates a persistent (bind-mounted) network namespace from the +// given netns path, i.e. /proc//ns/net, and returns the new full path to +// the bind mounted file in the netns run dir. +func NewNSFrom(fromNetns string) (string, error) { nsRunDir, err := GetNSRunDir() if err != nil { - return nil, err + return "", err } - // Create the directory for mounting network namespaces - // This needs to be a shared mountpoint in case it is mounted in to - // other namespaces (containers) - err = os.MkdirAll(nsRunDir, 0o755) + err = makeNetnsDir(nsRunDir) if err != nil { - return nil, err + return "", err } - // Remount the namespace directory shared. This will fail if it is not - // already a mountpoint, so bind-mount it on to itself to "upgrade" it - // to a mountpoint. - err = unix.Mount("", nsRunDir, "none", unix.MS_SHARED|unix.MS_REC, "") - if err != nil { - if err != unix.EINVAL { - return nil, fmt.Errorf("mount --make-rshared %s failed: %q", nsRunDir, err) + for i := 0; i < 10000; i++ { + nsName, err := getRandomNetnsName() + if err != nil { + return "", err } + nsPath := filepath.Join(nsRunDir, nsName) - // Recursively remount /run/netns on itself. The recursive flag is - // so that any existing netns bindmounts are carried over. - err = unix.Mount(nsRunDir, nsRunDir, "none", unix.MS_BIND|unix.MS_REC, "") + // create an empty file to use as at the mount point + err = createNetnsFile(nsPath) if err != nil { - return nil, fmt.Errorf("mount --rbind %s %s failed: %q", nsRunDir, nsRunDir, err) + // retry when the name already exists + if errors.Is(err, os.ErrExist) { + continue + } + return "", err } - // Now we can make it shared - err = unix.Mount("", nsRunDir, "none", unix.MS_SHARED|unix.MS_REC, "") + err = unix.Mount(fromNetns, nsPath, "none", unix.MS_BIND|unix.MS_SHARED|unix.MS_REC, "") if err != nil { - return nil, fmt.Errorf("mount --make-rshared %s failed: %q", nsRunDir, err) + // Do not leak the ns on errors + _ = os.RemoveAll(nsPath) + return "", fmt.Errorf("failed to bind mount ns at %s: %v", nsPath, err) } + return nsPath, nil } - nsPath := path.Join(nsRunDir, name) - return newNSPath(nsPath) + return "", errNoFreeName } -func newNSPath(nsPath string) (ns.NetNS, error) { - // create an empty file at the mount point - mountPointFd, err := os.OpenFile(nsPath, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0o600) +func getRandomNetnsName() (string, error) { + b := make([]byte, 16) + _, err := rand.Reader.Read(b) if err != nil { - return nil, err + return "", fmt.Errorf("failed to generate random netns name: %v", err) } - if err := mountPointFd.Close(); err != nil { - return nil, err + return fmt.Sprintf("netns-%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:]), nil +} + +func makeNetnsDir(nsRunDir string) error { + err := os.MkdirAll(nsRunDir, 0o755) + if err != nil { + return err + } + // Important, the bind mount setup is racy if two process try to set it up in parallel. + // This can have very bad consequences because we end up with two duplicated mounts + // for the netns file that then might have a different parent mounts. + // Also because as root netns dir is also created by ip netns we should not race against them. + // Use a lock on the netns dir like they do, compare the iproute2 ip netns add code. + // https://github.com/iproute2/iproute2/blob/8b9d9ea42759c91d950356ca43930a975d0c352b/ip/ipnetns.c#L806-L815 + + dirFD, err := unix.Open(nsRunDir, unix.O_RDONLY|unix.O_DIRECTORY|unix.O_CLOEXEC, 0) + if err != nil { + return &os.PathError{Op: "open", Path: nsRunDir, Err: err} + } + // closing the fd will also unlock so we do not have to call flock(fd,LOCK_UN) + defer unix.Close(dirFD) + + err = unix.Flock(dirFD, unix.LOCK_EX) + if err != nil { + return fmt.Errorf("failed to lock %s dir: %w", nsRunDir, err) + } + + // Remount the namespace directory shared. This will fail with EINVAL + // if it is not already a mountpoint, so bind-mount it on to itself + // to "upgrade" it to a mountpoint. + err = unix.Mount("", nsRunDir, "none", unix.MS_SHARED|unix.MS_REC, "") + if err == nil { + return nil + } + if err != unix.EINVAL { + return fmt.Errorf("mount --make-rshared %s failed: %q", nsRunDir, err) + } + + // Recursively remount /run/netns on itself. The recursive flag is + // so that any existing netns bindmounts are carried over. + err = unix.Mount(nsRunDir, nsRunDir, "none", unix.MS_BIND|unix.MS_REC, "") + if err != nil { + return fmt.Errorf("mount --rbind %s %s failed: %q", nsRunDir, nsRunDir, err) } + // Now we can make it shared + err = unix.Mount("", nsRunDir, "none", unix.MS_SHARED|unix.MS_REC, "") + if err != nil { + return fmt.Errorf("mount --make-rshared %s failed: %q", nsRunDir, err) + } + + return nil +} + +// createNetnsFile created the file with O_EXCL to ensure there are no conflicts with others +// Callers should check for ErrExist and loop over it to find a free file. +func createNetnsFile(path string) error { + mountPointFd, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0o600) + if err != nil { + return err + } + return mountPointFd.Close() +} + +func newNSPath(nsPath string) (ns.NetNS, error) { + // create an empty file to use as at the mount point + err := createNetnsFile(nsPath) + if err != nil { + return nil, err + } // Ensure the mount point is cleaned up on errors; if the namespace // was successfully mounted this will have no effect because the file // is in-use diff --git a/vendor/github.com/containers/common/version/version.go b/vendor/github.com/containers/common/version/version.go index 4867ade0..3703dc8d 100644 --- a/vendor/github.com/containers/common/version/version.go +++ b/vendor/github.com/containers/common/version/version.go @@ -1,4 +1,4 @@ package version // Version is the version of the build. -const Version = "0.60.2" +const Version = "0.60.3" diff --git a/vendor/github.com/containers/podman/v5/libpod/container_internal_common.go b/vendor/github.com/containers/podman/v5/libpod/container_internal_common.go index 47f2401c..f95644a8 100644 --- a/vendor/github.com/containers/podman/v5/libpod/container_internal_common.go +++ b/vendor/github.com/containers/podman/v5/libpod/container_internal_common.go @@ -2900,8 +2900,10 @@ func (c *Container) fixVolumePermissions(v *ContainerNamedVolume) error { uid := int(c.config.Spec.Process.User.UID) gid := int(c.config.Spec.Process.User.GID) + idmapped := hasIdmapOption(v.Options) + // if the volume is mounted with "idmap", leave the IDs in from the current environment. - if c.config.IDMappings.UIDMap != nil && !hasIdmapOption(v.Options) { + if c.config.IDMappings.UIDMap != nil && !idmapped { p := idtools.IDPair{ UID: uid, GID: gid, @@ -2947,7 +2949,8 @@ func (c *Container) fixVolumePermissions(v *ContainerNamedVolume) error { if stat, ok := st.Sys().(*syscall.Stat_t); ok { uid, gid := int(stat.Uid), int(stat.Gid) - if c.config.IDMappings.UIDMap != nil { + // If the volume is idmapped then undo the conversion to obtain the desired UID/GID in the container + if c.config.IDMappings.UIDMap != nil && idmapped { p := idtools.IDPair{ UID: uid, GID: gid, diff --git a/vendor/github.com/containers/podman/v5/libpod/networking_linux.go b/vendor/github.com/containers/podman/v5/libpod/networking_linux.go index 3ffc9d71..9ffdc1d0 100644 --- a/vendor/github.com/containers/podman/v5/libpod/networking_linux.go +++ b/vendor/github.com/containers/podman/v5/libpod/networking_linux.go @@ -3,11 +3,8 @@ package libpod import ( - "crypto/rand" "fmt" "net" - "os" - "path/filepath" "github.com/containernetworking/plugins/pkg/ns" "github.com/containers/common/libnetwork/types" @@ -17,7 +14,6 @@ import ( "github.com/opencontainers/runtime-spec/specs-go" "github.com/sirupsen/logrus" "github.com/vishvananda/netlink" - "golang.org/x/sys/unix" ) // Create and configure a new network namespace for a container @@ -104,33 +100,10 @@ func (r *Runtime) createNetNS(ctr *Container) (n string, q map[string]types.Stat // Configure the network namespace using the container process func (r *Runtime) setupNetNS(ctr *Container) error { nsProcess := fmt.Sprintf("/proc/%d/ns/net", ctr.state.PID) - - b := make([]byte, 16) - - if _, err := rand.Reader.Read(b); err != nil { - return fmt.Errorf("failed to generate random netns name: %w", err) - } - nsPath, err := netns.GetNSRunDir() - if err != nil { - return err - } - nsPath = filepath.Join(nsPath, fmt.Sprintf("netns-%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])) - - if err := os.MkdirAll(filepath.Dir(nsPath), 0711); err != nil { - return err - } - - mountPointFd, err := os.Create(nsPath) + nsPath, err := netns.NewNSFrom(nsProcess) if err != nil { return err } - if err := mountPointFd.Close(); err != nil { - return err - } - - if err := unix.Mount(nsProcess, nsPath, "none", unix.MS_BIND, ""); err != nil { - return fmt.Errorf("cannot mount %s: %w", nsPath, err) - } networkStatus, err := r.configureNetNS(ctr, nsPath) diff --git a/vendor/github.com/containers/podman/v5/libpod/runtime_ctr.go b/vendor/github.com/containers/podman/v5/libpod/runtime_ctr.go index 3db6d6aa..a3f26cc5 100644 --- a/vendor/github.com/containers/podman/v5/libpod/runtime_ctr.go +++ b/vendor/github.com/containers/podman/v5/libpod/runtime_ctr.go @@ -513,16 +513,11 @@ func (r *Runtime) setupContainer(ctx context.Context, ctr *Container) (_ *Contai volOptions = append(volOptions, withSetAnon()) } - needsChown := true - // If volume-opts are set, parse and add driver opts. if len(vol.Options) > 0 { isDriverOpts := false driverOpts := make(map[string]string) for _, opts := range vol.Options { - if opts == "idmap" { - needsChown = false - } if strings.HasPrefix(opts, "volume-opt") { isDriverOpts = true driverOptKey, driverOptValue, err := util.ParseDriverOpts(opts) @@ -538,11 +533,7 @@ func (r *Runtime) setupContainer(ctx context.Context, ctr *Container) (_ *Contai } } - if needsChown { - volOptions = append(volOptions, WithVolumeUID(ctr.RootUID()), WithVolumeGID(ctr.RootGID())) - } else { - volOptions = append(volOptions, WithVolumeNoChown()) - } + volOptions = append(volOptions, WithVolumeUID(ctr.RootUID()), WithVolumeGID(ctr.RootGID())) _, err = r.newVolume(ctx, false, volOptions...) if err != nil { diff --git a/vendor/github.com/containers/podman/v5/pkg/specgen/generate/ports.go b/vendor/github.com/containers/podman/v5/pkg/specgen/generate/ports.go index 0575fc7c..a67419d8 100644 --- a/vendor/github.com/containers/podman/v5/pkg/specgen/generate/ports.go +++ b/vendor/github.com/containers/podman/v5/pkg/specgen/generate/ports.go @@ -158,7 +158,7 @@ func ParsePortMapping(portMappings []types.PortMapping, exposePorts map[uint16][ // First, we need to validate the ports passed in the specgen for _, port := range portMappings { // First, check proto - protocols, err := checkProtocol(port.Protocol, true) + protocols, err := checkProtocol(port.Protocol) if err != nil { return nil, err } @@ -356,7 +356,7 @@ func createPortMappings(s *specgen.SpecGenerator, imageData *libimage.ImageData) if port == 0 { return nil, nil, fmt.Errorf("cannot expose 0 as it is not a valid port number") } - protocols, err := checkProtocol(proto, false) + protocols, err := checkProtocol(proto) if err != nil { return nil, nil, fmt.Errorf("validating protocols for exposed port %d: %w", port, err) } @@ -377,7 +377,7 @@ func createPortMappings(s *specgen.SpecGenerator, imageData *libimage.ImageData) } // Check a string to ensure it is a comma-separated set of valid protocols -func checkProtocol(protocol string, allowSCTP bool) ([]string, error) { +func checkProtocol(protocol string) ([]string, error) { protocols := make(map[string]struct{}) splitProto := strings.Split(protocol, ",") // Don't error on duplicates - just deduplicate @@ -389,9 +389,6 @@ func checkProtocol(protocol string, allowSCTP bool) ([]string, error) { case protoUDP: protocols[protoUDP] = struct{}{} case protoSCTP: - if !allowSCTP { - return nil, fmt.Errorf("protocol SCTP is not allowed for exposed ports") - } protocols[protoSCTP] = struct{}{} default: return nil, fmt.Errorf("unrecognized protocol %q in port mapping", p) diff --git a/vendor/github.com/containers/podman/v5/pkg/specgen/namespaces.go b/vendor/github.com/containers/podman/v5/pkg/specgen/namespaces.go index f685ab3e..e5b99f89 100644 --- a/vendor/github.com/containers/podman/v5/pkg/specgen/namespaces.go +++ b/vendor/github.com/containers/podman/v5/pkg/specgen/namespaces.go @@ -11,9 +11,9 @@ import ( "github.com/containers/common/pkg/cgroups" "github.com/containers/podman/v5/libpod/define" "github.com/containers/podman/v5/pkg/namespaces" - "github.com/containers/podman/v5/pkg/rootless" "github.com/containers/podman/v5/pkg/util" "github.com/containers/storage/pkg/fileutils" + "github.com/containers/storage/pkg/unshare" storageTypes "github.com/containers/storage/types" spec "github.com/opencontainers/runtime-spec/specs-go" "github.com/opencontainers/runtime-tools/generate" @@ -160,10 +160,15 @@ func validateNetNS(n *Namespace) error { case Slirp: break case Pasta: - if rootless.IsRootless() { + // Check if we run rootless/in a userns. Do not use rootless.IsRootless() here. + // Pasta switches to nobody when running as root which causes it to fail while + // opening the netns owned by root. However when pasta is already in a userns + // it doesn't switch to nobody so it works there. + // https://github.com/containers/podman/issues/17840 + if unshare.IsRootless() { break } - return fmt.Errorf("pasta networking is only supported for rootless mode") + return fmt.Errorf("pasta networking is only supported for rootless mode or when inside a nested userns") case "", Default, Host, Path, FromContainer, FromPod, Private, NoNetwork, Bridge: break default: diff --git a/vendor/github.com/containers/podman/v5/version/rawversion/version.go b/vendor/github.com/containers/podman/v5/version/rawversion/version.go index 81e0e2bb..65dbc9a5 100644 --- a/vendor/github.com/containers/podman/v5/version/rawversion/version.go +++ b/vendor/github.com/containers/podman/v5/version/rawversion/version.go @@ -7,4 +7,4 @@ package rawversion // // NOTE: remember to bump the version at the top of the top-level README.md // file when this is bumped. -const RawVersion = "5.2.2" +const RawVersion = "5.2.3" diff --git a/vendor/modules.txt b/vendor/modules.txt index fd4ebc14..26ccc06e 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -113,7 +113,7 @@ github.com/containernetworking/cni/pkg/version # github.com/containernetworking/plugins v1.5.1 ## explicit; go 1.20 github.com/containernetworking/plugins/pkg/ns -# github.com/containers/buildah v1.37.2 +# github.com/containers/buildah v1.37.3 ## explicit; go 1.21.0 github.com/containers/buildah github.com/containers/buildah/bind @@ -140,7 +140,7 @@ github.com/containers/buildah/pkg/rusage github.com/containers/buildah/pkg/sshagent github.com/containers/buildah/pkg/util github.com/containers/buildah/util -# github.com/containers/common v0.60.2 +# github.com/containers/common v0.60.3 ## explicit; go 1.21.0 github.com/containers/common/internal github.com/containers/common/internal/attributedstring @@ -297,7 +297,7 @@ github.com/containers/ocicrypt/keywrap/pkcs7 github.com/containers/ocicrypt/spec github.com/containers/ocicrypt/utils github.com/containers/ocicrypt/utils/keyprovider -# github.com/containers/podman/v5 v5.2.2 +# github.com/containers/podman/v5 v5.2.3 ## explicit; go 1.21.0 github.com/containers/podman/v5/cmd/podman/parse github.com/containers/podman/v5/cmd/podman/registry @@ -729,8 +729,8 @@ github.com/moby/sys/mountinfo # github.com/moby/sys/sequential v0.5.0 ## explicit; go 1.17 github.com/moby/sys/sequential -# github.com/moby/sys/user v0.2.0 -## explicit; go 1.21 +# github.com/moby/sys/user v0.3.0 +## explicit; go 1.17 github.com/moby/sys/user # github.com/moby/term v0.5.0 ## explicit; go 1.18