containers: detect overlapping mappings
when the container specifies some mappings to be applied, verify that they are not overlapping and give a clearer error message. Closes: https://github.com/containers/storage/issues/1127 Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
This commit is contained in:
parent
7877039211
commit
7e610596cf
|
|
@ -324,6 +324,12 @@ func (r *containerStore) Create(id string, names []string, image, layer, metadat
|
|||
fmt.Sprintf("the container name \"%s\" is already in use by \"%s\". You have to remove that container to be able to reuse that name.", name, r.byname[name].ID))
|
||||
}
|
||||
}
|
||||
if err := hasOverlappingRanges(options.UIDMap); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := hasOverlappingRanges(options.GIDMap); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err == nil {
|
||||
container = &Container{
|
||||
ID: id,
|
||||
|
|
|
|||
|
|
@ -55,4 +55,6 @@ var (
|
|||
ErrStoreIsReadOnly = types.ErrStoreIsReadOnly
|
||||
// ErrNotSupported is returned when the requested functionality is not supported.
|
||||
ErrNotSupported = types.ErrNotSupported
|
||||
// ErrInvalidMappings is returned when the specified mappings are invalid.
|
||||
ErrInvalidMappings = types.ErrInvalidMappings
|
||||
)
|
||||
|
|
|
|||
45
idset.go
45
idset.go
|
|
@ -1,6 +1,9 @@
|
|||
package storage
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/containers/storage/pkg/idtools"
|
||||
"github.com/google/go-intervals/intervalset"
|
||||
"github.com/pkg/errors"
|
||||
|
|
@ -218,3 +221,45 @@ func maxInt(a, b int) int {
|
|||
}
|
||||
return a
|
||||
}
|
||||
|
||||
func hasOverlappingRanges(mappings []idtools.IDMap) error {
|
||||
hostIntervals := intervalset.Empty()
|
||||
containerIntervals := intervalset.Empty()
|
||||
|
||||
var conflicts []string
|
||||
|
||||
for _, m := range mappings {
|
||||
c := interval{start: m.ContainerID, end: m.ContainerID + m.Size}
|
||||
h := interval{start: m.HostID, end: m.HostID + m.Size}
|
||||
|
||||
added := false
|
||||
overlaps := false
|
||||
|
||||
containerIntervals.IntervalsBetween(c, func(x intervalset.Interval) bool {
|
||||
overlaps = true
|
||||
return false
|
||||
})
|
||||
if overlaps {
|
||||
conflicts = append(conflicts, fmt.Sprintf("%v:%v:%v", m.ContainerID, m.HostID, m.Size))
|
||||
added = true
|
||||
}
|
||||
containerIntervals.Add(intervalset.NewSet([]intervalset.Interval{c}))
|
||||
|
||||
hostIntervals.IntervalsBetween(h, func(x intervalset.Interval) bool {
|
||||
overlaps = true
|
||||
return false
|
||||
})
|
||||
if overlaps && !added {
|
||||
conflicts = append(conflicts, fmt.Sprintf("%v:%v:%v", m.ContainerID, m.HostID, m.Size))
|
||||
}
|
||||
hostIntervals.Add(intervalset.NewSet([]intervalset.Interval{h}))
|
||||
}
|
||||
|
||||
if conflicts != nil {
|
||||
if len(conflicts) == 1 {
|
||||
return errors.Wrapf(ErrInvalidMappings, "the specified UID and/or GID mapping %s conflicts with other mappings", conflicts[0])
|
||||
}
|
||||
return errors.Wrapf(ErrInvalidMappings, "the specified UID and/or GID mappings %s conflict with other mappings", strings.Join(conflicts, ", "))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -922,3 +922,35 @@ func TestIntervalEncompass(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestOverlappingMappings(t *testing.T) {
|
||||
mappings := []idtools.IDMap{{ContainerID: 0, HostID: 1000, Size: 65536}, {ContainerID: 0, HostID: 1000, Size: 65536}}
|
||||
if err := hasOverlappingRanges(mappings); err == nil {
|
||||
t.Errorf("mappings = %v, expected to be overlapping", mappings)
|
||||
}
|
||||
|
||||
mappings = []idtools.IDMap{{ContainerID: 0, HostID: 1000, Size: 65536}, {ContainerID: 65536, HostID: 5000, Size: 65536}}
|
||||
if err := hasOverlappingRanges(mappings); err == nil {
|
||||
t.Errorf("mappings = %v, expected to be overlapping", mappings)
|
||||
}
|
||||
|
||||
mappings = []idtools.IDMap{{ContainerID: 0, HostID: 1000, Size: 65536}, {ContainerID: 0, HostID: 5000 + 65536, Size: 65536}}
|
||||
if err := hasOverlappingRanges(mappings); err == nil {
|
||||
t.Errorf("mappings = %v, expected to be overlapping", mappings)
|
||||
}
|
||||
|
||||
mappings = []idtools.IDMap{{ContainerID: 0, HostID: 1000, Size: 65536}, {ContainerID: 0, HostID: 1000 + 65536, Size: 65536}}
|
||||
if err := hasOverlappingRanges(mappings); err == nil {
|
||||
t.Errorf("mappings = %v, expected to be overlapping", mappings)
|
||||
}
|
||||
|
||||
mappings = []idtools.IDMap{{ContainerID: 0, HostID: 0, Size: 65536}, {ContainerID: 65536, HostID: 65536, Size: 65536}}
|
||||
if err := hasOverlappingRanges(mappings); err != nil {
|
||||
t.Errorf("mappings = %v, expected to not be overlapping", mappings)
|
||||
}
|
||||
|
||||
mappings = []idtools.IDMap{{ContainerID: 0, HostID: 0, Size: 65536}, {ContainerID: 1 * 65536, HostID: 1 * 65536, Size: 65536}, {ContainerID: 2 * 65536, HostID: 2 * 65536, Size: 65536}}
|
||||
if err := hasOverlappingRanges(mappings); err != nil {
|
||||
t.Errorf("mappings = %v, expected to not be overlapping", mappings)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,4 +55,6 @@ var (
|
|||
ErrStoreIsReadOnly = errors.New("called a write method on a read-only store")
|
||||
// ErrNotSupported is returned when the requested functionality is not supported.
|
||||
ErrNotSupported = errors.New("not supported")
|
||||
// ErrInvalidMappings is returned when the specified mappings are invalid.
|
||||
ErrInvalidMappings = errors.New("invalid mappings specified")
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in New Issue