store: use canonical image mapping when mounting

Ensure that a mapped layer with the canonical mapping is created if
one doesn't already exist.  Previously, any layer was used regardless
of its mapping, which resulted in the mounted image having incorrect
file ownership, depending on what mapping was found.

Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
This commit is contained in:
Giuseppe Scrivano 2025-03-17 12:15:34 +01:00
parent 7082298e07
commit 360c002932
No known key found for this signature in database
GPG Key ID: 67E38F7A8BA21772
2 changed files with 107 additions and 37 deletions

132
store.go
View File

@ -2830,7 +2830,11 @@ func (s *store) Version() ([][2]string, error) {
return [][2]string{}, nil
}
func (s *store) mount(id string, options drivers.MountOpts) (string, error) {
func (s *store) MountImage(id string, mountOpts []string, mountLabel string) (string, error) {
if err := validateMountOptions(mountOpts); err != nil {
return "", err
}
// We need to make sure the home mount is present when the Mount is done, which happens by possibly reinitializing the graph driver
// in startUsingGraphDriver().
if err := s.startUsingGraphDriver(); err != nil {
@ -2842,57 +2846,61 @@ func (s *store) mount(id string, options drivers.MountOpts) (string, error) {
if err != nil {
return "", err
}
if options.UidMaps != nil || options.GidMaps != nil {
options.DisableShifting = !s.canUseShifting(options.UidMaps, options.GidMaps)
}
var imageHomeStore roImageStore
// function used to have a scope for rlstore.StopWriting()
tryMount := func() (string, error) {
if err := rlstore.startWriting(); err != nil {
if err := rlstore.startWriting(); err != nil {
return "", err
}
defer rlstore.stopWriting()
for _, s := range lstores {
if err := s.startReading(); err != nil {
return "", err
}
defer rlstore.stopWriting()
if rlstore.Exists(id) {
return rlstore.Mount(id, options)
}
return "", nil
defer s.stopReading()
}
mountPoint, err := tryMount()
if mountPoint != "" || err != nil {
return mountPoint, err
if err := s.imageStore.startWriting(); err != nil {
return "", err
}
defer s.imageStore.stopWriting()
// check if the layer is in a read-only store, and return a better error message
for _, store := range lstores {
if err := store.startReading(); err != nil {
return "", err
}
exists := store.Exists(id)
store.stopReading()
if exists {
return "", fmt.Errorf("mounting read/only store images is not allowed: %w", ErrStoreIsReadOnly)
cimage, err := s.imageStore.Get(id)
if err == nil {
imageHomeStore = s.imageStore
} else {
for _, s := range s.roImageStores {
if err := s.startReading(); err != nil {
return "", err
}
defer s.stopReading()
cimage, err = s.Get(id)
if err == nil {
imageHomeStore = s
break
}
}
}
if cimage == nil {
return "", fmt.Errorf("locating image with ID %q: %w", id, ErrImageUnknown)
}
return "", ErrLayerUnknown
}
func (s *store) MountImage(id string, mountOpts []string, mountLabel string) (string, error) {
// Append ReadOnly option to mountOptions
img, err := s.Image(id)
idmappingsOpts := types.IDMappingOptions{
HostUIDMapping: true,
HostGIDMapping: true,
}
ilayer, err := s.imageTopLayerForMapping(cimage, imageHomeStore, rlstore, lstores, idmappingsOpts)
if err != nil {
return "", err
}
if err := validateMountOptions(mountOpts); err != nil {
return "", err
if len(ilayer.UIDMap) > 0 || len(ilayer.GIDMap) > 0 {
return "", fmt.Errorf("cannot create an image with canonical UID/GID mappings in a read-only store")
}
options := drivers.MountOpts{
MountLabel: mountLabel,
Options: append(mountOpts, "ro"),
}
return s.mount(img.TopLayer, options)
return rlstore.Mount(ilayer.ID, options)
}
func (s *store) Mount(id, mountLabel string) (string, error) {
@ -2914,7 +2922,43 @@ func (s *store) Mount(id, mountLabel string) (string, error) {
}
}
}
return s.mount(id, options)
// We need to make sure the home mount is present when the Mount is done, which happens by possibly reinitializing the graph driver
// in startUsingGraphDriver().
if err := s.startUsingGraphDriver(); err != nil {
return "", err
}
defer s.stopUsingGraphDriver()
rlstore, lstores, err := s.bothLayerStoreKindsLocked()
if err != nil {
return "", err
}
if options.UidMaps != nil || options.GidMaps != nil {
options.DisableShifting = !s.canUseShifting(options.UidMaps, options.GidMaps)
}
if err := rlstore.startWriting(); err != nil {
return "", err
}
defer rlstore.stopWriting()
if rlstore.Exists(id) {
return rlstore.Mount(id, options)
}
// check if the layer is in a read-only store, and return a better error message
for _, store := range lstores {
if err := store.startReading(); err != nil {
return "", err
}
exists := store.Exists(id)
store.stopReading()
if exists {
return "", fmt.Errorf("mounting read/only store images is not allowed: %w", ErrStoreIsReadOnly)
}
}
return "", ErrLayerUnknown
}
func (s *store) Mounted(id string) (int, error) {
@ -2938,7 +2982,23 @@ func (s *store) UnmountImage(id string, force bool) (bool, error) {
if err != nil {
return false, err
}
return s.Unmount(img.TopLayer, force)
return writeToLayerStore(s, func(lstore rwLayerStore) (bool, error) {
for _, layerID := range img.MappedTopLayers {
l, err := lstore.Get(layerID)
if err != nil {
if err == ErrLayerUnknown {
continue
}
return false, err
}
// check if the layer with the canonical mapping is in the mapped top layers
if len(l.UIDMap) == 0 && len(l.GIDMap) == 0 {
return lstore.unmount(l.ID, force, false)
}
}
return lstore.unmount(img.TopLayer, force, false)
})
}
func (s *store) Unmount(id string, force bool) (bool, error) {

View File

@ -290,7 +290,17 @@ load helpers
done
# Create new containers based on the layer.
imagename=idmappedimage
storage create-image --name=$imagename $lowerlayer
run storage create-image --name=$imagename $lowerlayer
[ "$status" -eq 0 ]
run storage --debug=false mount -r $imagename
[ "$status" -eq 0 ]
mountpoint="$output"
run stat -c %u:%g $mountpoint/file1
# make sure the file shows the correct ownership after the image is mounted
[ "$output" == "0:0" ]
run storage umount $imagename
[ "$status" -eq 0 ]
run storage --debug=false create-container --hostuidmap --hostgidmap $imagename
[ "$status" -eq 0 ]