Merge pull request #29899 from Monster-GM/fix/export-keep-id-ownership
Some checks are pending
ci / path-filter (push) Waiting to run
ci / Validate source code changes (push) Waiting to run
ci / Cross Build (Linux, FreeBSD) (push) Waiting to run
ci / build debian-sid (push) Waiting to run
ci / build fedora-current (push) Waiting to run
ci / build fedora-prior (push) Waiting to run
ci / build fedora-rawhide (push) Waiting to run
ci / windows installer hyperv (push) Waiting to run
ci / windows installer wsl (push) Waiting to run
ci / macos installer (push) Waiting to run
ci / int local root debian-sid (push) Blocked by required conditions
ci / sys local root debian-sid (push) Blocked by required conditions
ci / int local rootless debian-sid (push) Blocked by required conditions
ci / sys local rootless debian-sid (push) Blocked by required conditions
ci / int remote root debian-sid (push) Blocked by required conditions
ci / sys remote root debian-sid (push) Blocked by required conditions
ci / bud local root fedora-current (push) Blocked by required conditions
ci / int local root fedora-current (push) Blocked by required conditions
ci / sys local root fedora-current (push) Blocked by required conditions
ci / int local rootless fedora-current (push) Blocked by required conditions
ci / sys local rootless fedora-current (push) Blocked by required conditions
ci / bud remote root fedora-current (push) Blocked by required conditions
ci / int remote root fedora-current (push) Blocked by required conditions
ci / sys remote root fedora-current (push) Blocked by required conditions
ci / int remote rootless fedora-current (push) Blocked by required conditions
ci / sys remote rootless fedora-current (push) Blocked by required conditions
ci / int local root fedora-prior (push) Blocked by required conditions
ci / sys local root fedora-prior (push) Blocked by required conditions
ci / int local rootless fedora-prior (push) Blocked by required conditions
ci / sys local rootless fedora-prior (push) Blocked by required conditions
ci / int remote root fedora-prior (push) Blocked by required conditions
ci / sys remote root fedora-prior (push) Blocked by required conditions
ci / int local root fedora-rawhide (push) Blocked by required conditions
ci / sys local root fedora-rawhide (push) Blocked by required conditions
ci / int local rootless fedora-rawhide (push) Blocked by required conditions
ci / sys local rootless fedora-rawhide (push) Blocked by required conditions
ci / int remote root fedora-rawhide (push) Blocked by required conditions
ci / sys remote root fedora-rawhide (push) Blocked by required conditions
ci / apiv2 root fedora-current (push) Blocked by required conditions
ci / bindings root fedora-current (push) Blocked by required conditions
ci / compose_v2 root fedora-current (push) Blocked by required conditions
ci / docker_py root fedora-current (push) Blocked by required conditions
ci / unit root fedora-current (push) Blocked by required conditions
ci / apiv2 rootless fedora-current (push) Blocked by required conditions
ci / compose_v2 rootless fedora-current (push) Blocked by required conditions
ci / farm rootless fedora-current (push) Blocked by required conditions
ci / unit rootless fedora-current (push) Blocked by required conditions
ci / upgrade v5.3.1 root fedora-current (push) Blocked by required conditions
ci / upgrade v5.6.2 root fedora-current (push) Blocked by required conditions
ci / machine linux amd64 (push) Blocked by required conditions
ci / windows unit (push) Blocked by required conditions
ci / windows e2e (push) Blocked by required conditions
ci / windows machine hyperv (push) Blocked by required conditions
ci / windows machine wsl (push) Blocked by required conditions
ci / macos machine applehv (push) Blocked by required conditions
ci / macos machine libkrun (push) Blocked by required conditions
ci / Total Success (push) Blocked by required conditions
zizmor: GitHub Actions Security Analysis / Zizmor (push) Waiting to run

fix: preserve ownership when exporting keep-id containers
This commit is contained in:
Giuseppe Scrivano 2026-10-06 16:04:29 +02:00 • committed by GitHub
commit a973b14e38
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 46 additions and 1 deletions

View file

@ -48,6 +48,7 @@ import (
"go.podman.io/podman/v6/pkg/systemd/notifyproxy"
"go.podman.io/podman/v6/pkg/util"
"go.podman.io/storage"
"go.podman.io/storage/pkg/archive"
"go.podman.io/storage/pkg/chrootarchive"
"go.podman.io/storage/pkg/directory"
"go.podman.io/storage/pkg/fileutils"
@ -791,7 +792,10 @@ func (c *Container) export(out io.Writer) error {
}()
}
input, err := chrootarchive.Tar(mountPoint, nil, mountPoint)
input, err := chrootarchive.Tar(mountPoint, &archive.TarOptions{
UIDMaps: c.config.IDMappings.UIDMap,
GIDMaps: c.config.IDMappings.GIDMap,
}, mountPoint)
if err != nil {
return fmt.Errorf("reading container directory %q: %w", c.ID(), err)
}

View file

@ -3,8 +3,12 @@
package integration
import (
"archive/tar"
"fmt"
"io"
"os"
"path/filepath"
"strings"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
@ -69,4 +73,41 @@ var _ = Describe("Podman export", func() {
Expect(events[0]).To(ContainSubstring("export"))
Expect(events[0]).To(ContainSubstring(cid))
})
It("podman export preserves ownership with keep-id user namespaces", func() {
SkipIfNotRootless("rootless --userns=keep-id stores host-mapped IDs in the container filesystem")
// Mirrors the reproducer of #29856: an image with a dedicated
// user (UID/GID 1000), a keep-id container that is created but
// never started, and an export whose tar headers must show
// container ownership (user 1000/1000, root-owned parents).
imageName := "test-export-keepid-user-image"
containerfile := fmt.Sprintf("FROM %s\nRUN adduser -D -u 1000 user && touch /home/user/newfile && chown -R 1000:1000 /home/user\n", ALPINE)
podmanTest.BuildImage(containerfile, imageName, "false", "--network=none")
create := podmanTest.PodmanExitCleanly("create", "--userns=keep-id", imageName)
cid := strings.TrimSpace(create.OutputToString())
outfile := filepath.Join(podmanTest.TempDir, "keep-id-export.tar")
podmanTest.PodmanExitCleanly("export", "-o", outfile, cid)
file, err := os.Open(outfile)
Expect(err).ToNot(HaveOccurred())
defer file.Close()
reader := tar.NewReader(file)
owners := map[string]string{}
for {
header, err := reader.Next()
if err == io.EOF {
break
}
Expect(err).ToNot(HaveOccurred())
owners[strings.TrimSuffix(header.Name, "/")] = fmt.Sprintf("%d/%d", header.Uid, header.Gid)
}
Expect(owners["home"]).To(Equal("0/0"), "home/ should be owned by root in the exported tar")
Expect(owners["home/user"]).To(Equal("1000/1000"), "home/user should keep container ownership in the exported tar")
Expect(owners["home/user/newfile"]).To(Equal("1000/1000"), "files under home/user should keep container ownership in the exported tar")
})
})