Skip to content

Commit ebcef3e

Browse files
committed
specconv: temporarily allow userns path and mapping if they match
It turns out that the error added in commit 09822c3 ("configs: disallow ambiguous userns and timens configurations") causes issues with containerd and CRIO because they pass both userns mappings and a userns path. These configurations are broken, but to avoid the regression in this one case, output a warning to tell the user that the configuration is incorrect but we will continue to use it if and only if the configured mappings are identical to the mappings of the provided namespace. Fixes: 09822c3 ("configs: disallow ambiguous userns and timens configurations") Signed-off-by: Aleksa Sarai <[email protected]>
1 parent 99f7fa1 commit ebcef3e

3 files changed

Lines changed: 36 additions & 7 deletions

File tree

libcontainer/specconv/spec_linux.go

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -973,18 +973,32 @@ func setupUserNamespace(spec *specs.Spec, config *configs.Config) error {
973973
config.GIDMappings = toConfigIDMap(spec.Linux.GIDMappings)
974974
}
975975
if path := config.Namespaces.PathOf(configs.NEWUSER); path != "" {
976-
// We cannot allow uid or gid mappings to be set if we are also asked
977-
// to join a userns.
978-
if config.UIDMappings != nil || config.GIDMappings != nil {
979-
return errors.New("user namespaces enabled, but both namespace path and mapping specified -- you may only provide one")
980-
}
981976
// Cache the current userns mappings in our configuration, so that we
982977
// can calculate uid and gid mappings within runc. These mappings are
983978
// never used for configuring the container if the path is set.
984979
uidMap, gidMap, err := userns.GetUserNamespaceMappings(path)
985980
if err != nil {
986981
return fmt.Errorf("failed to cache mappings for userns: %w", err)
987982
}
983+
// We cannot allow uid or gid mappings to be set if we are also asked
984+
// to join a userns.
985+
if config.UIDMappings != nil || config.GIDMappings != nil {
986+
// FIXME: It turns out that containerd and CRIO pass both a userns
987+
// path and the mappings of the namespace in the same config.json.
988+
// Such a configuration is technically not valid, but we used to
989+
// require mappings be specified, and thus users worked around our
990+
// bug -- so we can't regress it at the moment. But we also don't
991+
// want to produce broken behaviour if the mapping doesn't match
992+
// the userns. So (for now) we output a warning if the actual
993+
// userns mappings match the configuration, otherwise we return an
994+
// error.
995+
if !userns.IsSameMapping(uidMap, config.UIDMappings) ||
996+
!userns.IsSameMapping(gidMap, config.GIDMappings) {
997+
return errors.New("user namespaces enabled, but both namespace path and non-matching mapping specified -- you may only provide one")
998+
}
999+
logrus.Warnf("config.json has both a userns path to join and a matching userns mapping specified -- you may only provide one. Future versions of runc may return an error with this configuration, please report a bug on <https://github.com/opencontainers/runc> if you see this warning and cannot update your configuration.")
1000+
}
1001+
9881002
config.UIDMappings = uidMap
9891003
config.GIDMappings = gidMap
9901004
logrus.WithFields(logrus.Fields{

libcontainer/specconv/spec_linux_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -637,8 +637,8 @@ func TestUserNamespaceMappingAndPath(t *testing.T) {
637637
Spec: spec,
638638
})
639639

640-
if !strings.Contains(err.Error(), "user namespaces enabled, but both namespace path and mapping specified") {
641-
t.Errorf("user namespace with mapping and namespace path should be forbidden")
640+
if !strings.Contains(err.Error(), "both namespace path and non-matching mapping specified") {
641+
t.Errorf("user namespace with path and non-matching mapping should be forbidden, got error %v", err)
642642
}
643643
}
644644

libcontainer/userns/userns_maps_linux.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,3 +169,18 @@ func GetUserNamespaceMappings(nsPath string) (uidMap, gidMap []configs.IDMap, er
169169

170170
return uidMap, gidMap, nil
171171
}
172+
173+
// IsSameMapping returns whether or not the two id mappings are the same. Note
174+
// that if the order of the mappings is different, or a mapping has been split,
175+
// the mappings will be considered different.
176+
func IsSameMapping(a, b []configs.IDMap) bool {
177+
if len(a) != len(b) {
178+
return false
179+
}
180+
for idx := range a {
181+
if a[idx] != b[idx] {
182+
return false
183+
}
184+
}
185+
return true
186+
}

0 commit comments

Comments
 (0)