Skip to content

Commit f3ea522

Browse files
authored
Merge pull request #4889 from tych0/allow-ucounts
libcontainer/validator: allow setting user.* sysctls inside userns
2 parents 55c90aa + 70d88bc commit f3ea522

File tree

2 files changed

+58
-0
lines changed

2 files changed

+58
-0
lines changed

libcontainer/configs/validate/validator.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,30 @@ func sysctl(config *configs.Config) error {
274274
return fmt.Errorf("sysctl %q is not allowed as it conflicts with the OCI %q field", s, "hostname")
275275
}
276276
}
277+
278+
if strings.HasPrefix(s, "user.") {
279+
280+
// while it is technically true that a non-userns
281+
// container can write to /proc/sys/user on behalf of
282+
// the init_user_ns, it was not previously supported,
283+
// and doesn't guarantee that someone else spawns a
284+
// different container and writes there, changing the
285+
// values. in particular, setting something like
286+
// max_user_namespaces to non-zero could be a vector to
287+
// use 0-days where the admin had previously disabled
288+
// them.
289+
//
290+
// additionally, this setting affects other host
291+
// processes that are not container related.
292+
//
293+
// so let's refuse this unless we know for sure it
294+
// won't touch anything else.
295+
if !config.Namespaces.Contains(configs.NEWUSER) {
296+
return fmt.Errorf("setting ucounts without a user namespace not allowed: %v", s)
297+
}
298+
continue
299+
}
300+
277301
return fmt.Errorf("sysctl %q is not in a separate kernel namespace", s)
278302
}
279303

libcontainer/configs/validate/validator_test.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1019,6 +1019,40 @@ func TestValidateNetDevices(t *testing.T) {
10191019
}
10201020
}
10211021

1022+
func TestValidateUserSysctlWithUserNamespace(t *testing.T) {
1023+
if _, err := os.Stat("/proc/self/ns/user"); os.IsNotExist(err) {
1024+
t.Skip("Test requires userns.")
1025+
}
1026+
config := &configs.Config{
1027+
Rootfs: "/var",
1028+
Sysctl: map[string]string{"user.max_inotify_watches": "8192"},
1029+
Namespaces: configs.Namespaces(
1030+
[]configs.Namespace{
1031+
{Type: configs.NEWUSER},
1032+
},
1033+
),
1034+
UIDMappings: []configs.IDMap{{HostID: 0, ContainerID: 123, Size: 100}},
1035+
GIDMappings: []configs.IDMap{{HostID: 0, ContainerID: 123, Size: 100}},
1036+
}
1037+
1038+
err := Validate(config)
1039+
if err != nil {
1040+
t.Errorf("Expected error to not occur with user.* sysctl and NEWUSER namespace: %+v", err)
1041+
}
1042+
}
1043+
1044+
func TestValidateUserSysctlWithoutUserNamespace(t *testing.T) {
1045+
config := &configs.Config{
1046+
Rootfs: "/var",
1047+
Sysctl: map[string]string{"user.max_inotify_watches": "8192"},
1048+
}
1049+
1050+
err := Validate(config)
1051+
if err == nil {
1052+
t.Error("Expected error to occur with user.* sysctl without NEWUSER namespace but it was nil")
1053+
}
1054+
}
1055+
10221056
func TestDevValidName(t *testing.T) {
10231057
testCases := []struct {
10241058
name string

0 commit comments

Comments
 (0)