From ec6b3f7597b3755d4aec72154a3df8990f6ab910 Mon Sep 17 00:00:00 2001 From: Aleksa Sarai Date: Mon, 9 May 2016 00:25:27 +1000 Subject: [PATCH] validator: ensure user doesn't try to mount /sys without userns Inside a user namespace, mount permissions become more nuanced. sysfs requires you to have either CAP_SYS_ADMIN in the root user namespace (for us this means that we're not using a user namespace) or that you have CAP_SYS_ADMIN in the user namespace the network namespace was created in. This means that having just a user namespace and no private network namespace will result in errors when mounting sysfs[1]. Warn the user about this in the validator. [1]: http://lists.linuxfoundation.org/pipermail/containers/2013-August/033388.html Signed-off-by: Aleksa Sarai --- libcontainer/configs/validate/validator.go | 9 ++++++++ .../configs/validate/validator_test.go | 22 +++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/libcontainer/configs/validate/validator.go b/libcontainer/configs/validate/validator.go index 448cde27a27..3ea007dc8c5 100644 --- a/libcontainer/configs/validate/validator.go +++ b/libcontainer/configs/validate/validator.go @@ -64,7 +64,16 @@ func (v *ConfigValidator) network(config *configs.Config) error { if len(config.Networks) > 0 || len(config.Routes) > 0 { return fmt.Errorf("unable to apply network settings without a private NET namespace") } + + if config.Namespaces.Contains(configs.NEWUSER) { + for _, mount := range config.Mounts { + if mount.Device == "sysfs" { + return fmt.Errorf("unable to mount sysfs in a USER namespace without a private NET namespace") + } + } + } } + return nil } diff --git a/libcontainer/configs/validate/validator_test.go b/libcontainer/configs/validate/validator_test.go index 991aee23718..948c7389664 100644 --- a/libcontainer/configs/validate/validator_test.go +++ b/libcontainer/configs/validate/validator_test.go @@ -36,6 +36,28 @@ func TestValidateWithInvalidRootfs(t *testing.T) { } } +func TestValidateSysfsWithoutNETNamespace(t *testing.T) { + config := &configs.Config{ + Rootfs: "/var", + Namespaces: []configs.Namespace{{Type: configs.NEWUSER}}, + UidMappings: []configs.IDMap{{ContainerID: 0, HostID: 1000, Size: 1}}, + GidMappings: []configs.IDMap{{ContainerID: 0, HostID: 1000, Size: 1}}, + Mounts: []*configs.Mount{ + { + Destination: "/sys", + Device: "sysfs", + Source: "sysfs", + }, + }, + } + + validator := validate.New() + err := validator.Validate(config) + if err == nil { + t.Error("Expected error to occur but it was nil") + } +} + func TestValidateNetworkWithoutNETNamespace(t *testing.T) { network := &configs.Network{Type: "loopback"} config := &configs.Config{