Merge pull request #29614 from jiwahn/fix-volume-import-permission

libpod: adjust permissions for imported volumes
This commit is contained in:
Matt Heon 2026-08-24 14:36:13 -04:00 committed by GitHub
commit 5aba1efe16
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 47 additions and 1 deletions

View file

@ -6,6 +6,7 @@ import (
"fmt"
"io"
"maps"
"os"
"time"
"github.com/sirupsen/logrus"
@ -104,7 +105,7 @@ type VolumeState struct {
// a container, the container will chown the volume to the container process
// UID/GID.
NeedsChown bool `json:"notYetChowned,omitempty"`
// Indicates that a copy-up event occurred during the current mount of
// CopiedUp indicates that a copy-up event occurred during the current mount of
// the volume into a container.
// We use this to determine if a chown is appropriate.
CopiedUp bool `json:"copiedUp,omitempty"`
@ -346,5 +347,22 @@ func (v *Volume) Import(r io.Reader) error {
return fmt.Errorf("extracting into volume %s: %w", v.Name(), err)
}
contents, err := os.ReadDir(mountPoint)
if err != nil {
return fmt.Errorf("reading contents of imported volume %s: %w", v.Name(), err)
}
if len(contents) != 0 {
v.lock.Lock()
defer v.lock.Unlock()
if err := v.update(); err != nil {
return err
}
if v.state.NeedsCopyUp && v.state.NeedsChown {
v.state.NeedsCopyUp = false
v.state.CopiedUp = true
return v.save()
}
}
return nil
}

View file

@ -120,6 +120,34 @@ var _ = Describe("Podman volume create", func() {
Expect(session.OutputToString()).To(ContainSubstring("hello"))
})
It("podman import volume preserves first mount permission adjustment", func() {
imageName := "volume-copyup-permissions:latest"
containerfile := fmt.Sprintf(`FROM %s
RUN mkdir -p /vol-target && chown 70:71 /vol-target && chmod 750 /vol-target && echo hello > /vol-target/test
`, ALPINE)
podmanTest.BuildImage(containerfile, imageName, "false")
volName := "my_vol_" + RandomString(10)
podmanTest.PodmanExitCleanly("volume", "create", volName)
session := podmanTest.PodmanExitCleanly("run", "--volume", volName+":/vol-target", imageName, "stat", "-c", "%u:%g %a", "/vol-target")
Expect(session.OutputToString()).To(Equal("70:71 750"))
helloTar := filepath.Join(podmanTest.TempDir, "hello.tar")
podmanTest.PodmanExitCleanly("volume", "export", volName, "--output", helloTar)
importedVolName := "my_vol_" + RandomString(10)
podmanTest.PodmanExitCleanly("volume", "create", importedVolName)
podmanTest.PodmanExitCleanly("volume", "import", importedVolName, helloTar)
session = podmanTest.PodmanExitCleanly("run", "--volume", importedVolName+":/vol-target", imageName, "stat", "-c", "%u:%g %a", "/vol-target")
Expect(session.OutputToString()).To(Equal("70:71 750"))
session = podmanTest.PodmanExitCleanly("run", "--volume", importedVolName+":/vol-target", imageName, "cat", "/vol-target/test")
Expect(session.OutputToString()).To(Equal("hello"))
})
It("podman import/export volume should fail", func() {
// try import on volume or source which does not exist
SkipIfRemote("Volume export check does not work with a remote client")