[lxc-devel] [lxd/master] config key & terminology fixes

brauner on Github lxc-bot at linuxcontainers.org
Fri Jul 3 13:36:14 UTC 2020


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 364 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20200703/7a081431/attachment.bin>
-------------- next part --------------
From 9b09647b1f06851cc8af566ac7c7851e66cb3302 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Fri, 3 Jul 2020 14:52:11 +0200
Subject: [PATCH 1/2] instance: update terminology I

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 lxd/instance/instance_utils.go | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/lxd/instance/instance_utils.go b/lxd/instance/instance_utils.go
index e9837df99b..3067478441 100644
--- a/lxd/instance/instance_utils.go
+++ b/lxd/instance/instance_utils.go
@@ -124,16 +124,16 @@ func ValidConfig(sysOS *sys.OS, config map[string]string, profile bool, expanded
 	}
 
 	_, rawSeccomp := config["raw.seccomp"]
-	_, whitelist := config["security.syscalls.whitelist"]
-	_, blacklist := config["security.syscalls.blacklist"]
-	blacklistDefault := shared.IsTrue(config["security.syscalls.blacklist_default"])
-	blacklistCompat := shared.IsTrue(config["security.syscalls.blacklist_compat"])
+	_, isAllow := config["security.syscalls.whitelist"]
+	_, isDeny := config["security.syscalls.blacklist"]
+	isDenyDefault := shared.IsTrue(config["security.syscalls.blacklist_default"])
+	isDenyCompat := shared.IsTrue(config["security.syscalls.blacklist_compat"])
 
-	if rawSeccomp && (whitelist || blacklist || blacklistDefault || blacklistCompat) {
+	if rawSeccomp && (isAllow || isDeny || isDenyDefault || isDenyCompat) {
 		return fmt.Errorf("raw.seccomp is mutually exclusive with security.syscalls*")
 	}
 
-	if whitelist && (blacklist || blacklistDefault || blacklistCompat) {
+	if isAllow && (isDeny || isDenyDefault || isDenyCompat) {
 		return fmt.Errorf("security.syscalls.whitelist is mutually exclusive with security.syscalls.blacklist*")
 	}
 
@@ -230,7 +230,7 @@ func lxcValidConfig(rawLxc string) error {
 			}
 		}
 
-		// Blacklist some keys
+		// block some keys
 		if key == "lxc.logfile" || key == "lxc.log.file" {
 			return fmt.Errorf("Setting lxc.logfile is not allowed")
 		}

From 946df3a2c4e32863b05af6c6357c3438606ef1b5 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Fri, 3 Jul 2020 15:33:13 +0200
Subject: [PATCH 2/2] instance: introduce
 container_syscall_filtering_allow_deny extension

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 doc/api-extensions.md          |  8 ++++++
 doc/instances.md               |  8 +++---
 lxd/daemon.go                  |  1 +
 lxd/instance/instance_utils.go | 51 ++++++++++++++++++++++++++++------
 lxd/seccomp/seccomp.go         | 45 ++++++++++++++++++++++--------
 scripts/bash/lxd-client        |  5 ++--
 shared/instance.go             |  4 +++
 test/suites/basic.sh           |  2 +-
 8 files changed, 97 insertions(+), 27 deletions(-)

diff --git a/doc/api-extensions.md b/doc/api-extensions.md
index ea699c5d7f..f009352b91 100644
--- a/doc/api-extensions.md
+++ b/doc/api-extensions.md
@@ -1098,3 +1098,11 @@ It introduces the new `--type` flag when creating custom storage volumes, and ac
 
 This extension adds a new `failure_domain` field to the `PUT /1.0/cluster/<node>` API,
 which can be used to set the failure domain of a node.
+
+## container\_syscall\_filtering\_allow\_deny\_syntax
+A number of new syscalls related container configuration keys were updated.
+
+ * `security.syscalls.deny_default`
+ * `security.syscalls.deny_compat`
+ * `security.syscalls.deny`
+ * `security.syscalls.allow`
diff --git a/doc/instances.md b/doc/instances.md
index 6663111ee9..ae25f602b1 100644
--- a/doc/instances.md
+++ b/doc/instances.md
@@ -81,16 +81,16 @@ security.privileged                         | boolean   | false             | no
 security.protection.delete                  | boolean   | false             | yes           | -                         | Prevents the instance from being deleted
 security.protection.shift                   | boolean   | false             | yes           | container                 | Prevents the instance's filesystem from being uid/gid shifted on startup
 security.secureboot                         | boolean   | true              | no            | virtual-machine           | Controls whether UEFI secure boot is enabled with the default Microsoft keys
-security.syscalls.blacklist                 | string    | -                 | no            | container                 | A '\n' separated list of syscalls to blacklist
-security.syscalls.blacklist\_compat         | boolean   | false             | no            | container                 | On x86\_64 this enables blocking of compat\_\* syscalls, it is a no-op on other arches
-security.syscalls.blacklist\_default        | boolean   | true              | no            | container                 | Enables the default syscall blacklist
+security.syscalls.deny                      | string    | -                 | no            | container                 | A '\n' separated list of syscalls to deny
+security.syscalls.deny\_compat              | boolean   | false             | no            | container                 | On x86\_64 this enables blocking of compat\_\* syscalls, it is a no-op on other arches
+security.syscalls.deny\_default             | boolean   | true              | no            | container                 | Enables the default syscall deny
 security.syscalls.intercept.mknod           | boolean   | false             | no            | container                 | Handles the `mknod` and `mknodat` system calls (allows creation of a limited subset of char/block devices)
 security.syscalls.intercept.mount           | boolean   | false             | no            | container                 | Handles the `mount` system call
 security.syscalls.intercept.mount.allowed   | string    | -                 | yes           | container                 | Specify a comma-separated list of filesystems that are safe to mount for processes inside the instance
 security.syscalls.intercept.mount.fuse      | string    | -                 | yes           | container                 | Whether to redirect mounts of a given filesystem to their fuse implemenation (e.g. ext4=fuse2fs)
 security.syscalls.intercept.mount.shift     | boolean   | false             | yes           | container                 | Whether to mount shiftfs on top of filesystems handled through mount syscall interception
 security.syscalls.intercept.setxattr        | boolean   | false             | no            | container                 | Handles the `setxattr` system call (allows setting a limited subset of restricted extended attributes)
-security.syscalls.whitelist                 | string    | -                 | no            | container                 | A '\n' separated list of syscalls to whitelist (mutually exclusive with security.syscalls.blacklist\*)
+security.syscalls.allow                     | string    | -                 | no            | container                 | A '\n' separated list of syscalls to allow (mutually exclusive with security.syscalls.deny\*)
 snapshots.schedule                          | string    | -                 | no            | -                         | Cron expression (`<minute> <hour> <dom> <month> <dow>`)
 snapshots.schedule.stopped                  | bool      | false             | no            | -                         | Controls whether or not stopped instances are to be snapshoted automatically
 snapshots.pattern                           | string    | snap%d            | no            | -                         | Pongo2 template string which represents the snapshot name (used for scheduled snapshots and unnamed snapshots)
diff --git a/lxd/daemon.go b/lxd/daemon.go
index 30357daddf..f04ceb58dd 100644
--- a/lxd/daemon.go
+++ b/lxd/daemon.go
@@ -610,6 +610,7 @@ func (d *Daemon) init() error {
 		"network_veth_router",
 		"cgroup2",
 		"pidfd",
+		"seccomp_allow_deny_syntax",
 	}
 	for _, extension := range lxcExtensions {
 		d.os.LXCFeatures[extension] = liblxc.HasApiExtension(extension)
diff --git a/lxd/instance/instance_utils.go b/lxd/instance/instance_utils.go
index 3067478441..5dd419c8b6 100644
--- a/lxd/instance/instance_utils.go
+++ b/lxd/instance/instance_utils.go
@@ -102,6 +102,24 @@ func CompareSnapshots(source Instance, target Instance) ([]Instance, []Instance,
 	return toSync, toDelete, nil
 }
 
+func exclusiveConfigKeys(key1 string, key2 string, config map[string]string) (val string, ok bool, err error) {
+	if config[key1] != "" && config[key2] != "" {
+		return "", false, fmt.Errorf("Mutually exclusive keys %s and %s are set", key1, key2)
+	}
+
+	val, ok = config[key1]
+	if ok {
+		return
+	}
+
+	val, ok = config[key2]
+	if ok {
+		return
+	}
+
+	return "", false, nil
+}
+
 // ValidConfig validates an instance's config.
 func ValidConfig(sysOS *sys.OS, config map[string]string, profile bool, expanded bool) error {
 	if config == nil {
@@ -124,20 +142,37 @@ func ValidConfig(sysOS *sys.OS, config map[string]string, profile bool, expanded
 	}
 
 	_, rawSeccomp := config["raw.seccomp"]
-	_, isAllow := config["security.syscalls.whitelist"]
-	_, isDeny := config["security.syscalls.blacklist"]
-	isDenyDefault := shared.IsTrue(config["security.syscalls.blacklist_default"])
-	isDenyCompat := shared.IsTrue(config["security.syscalls.blacklist_compat"])
+	_, isAllow, err := exclusiveConfigKeys("security.syscalls.allow", "security.syscalls.whitelist", config)
+	if err != nil {
+		return err
+	}
+
+	_, isDeny, err := exclusiveConfigKeys("security.syscalls.deny", "security.syscalls.blacklist", config)
+	if err != nil {
+		return err
+	}
+
+	val, _, err := exclusiveConfigKeys("security.syscalls.deny_default", "security.syscalls.blacklist_default", config)
+	if err != nil {
+		return err
+	}
+	isDenyDefault := shared.IsTrue(val)
+
+	val, _, err = exclusiveConfigKeys("security.syscalls.deny_compat", "security.syscalls.blacklist_compat", config)
+	if err != nil {
+		return err
+	}
+	isDenyCompat := shared.IsTrue(val)
 
 	if rawSeccomp && (isAllow || isDeny || isDenyDefault || isDenyCompat) {
 		return fmt.Errorf("raw.seccomp is mutually exclusive with security.syscalls*")
 	}
 
 	if isAllow && (isDeny || isDenyDefault || isDenyCompat) {
-		return fmt.Errorf("security.syscalls.whitelist is mutually exclusive with security.syscalls.blacklist*")
+		return fmt.Errorf("security.syscalls.allow is mutually exclusive with security.syscalls.deny*")
 	}
 
-	_, err := seccomp.SyscallInterceptMountFilter(config)
+	_, err = seccomp.SyscallInterceptMountFilter(config)
 	if err != nil {
 		return err
 	}
@@ -174,7 +209,7 @@ func validConfigKey(os *sys.OS, key string, value string) error {
 	if key == "raw.lxc" {
 		return lxcValidConfig(value)
 	}
-	if key == "security.syscalls.blacklist_compat" {
+	if key == "security.syscalls.deny_compat" || key == "security.syscalls.blacklist_compat" {
 		for _, arch := range os.Architectures {
 			if arch == osarch.ARCH_64BIT_INTEL_X86 ||
 				arch == osarch.ARCH_64BIT_ARMV8_LITTLE_ENDIAN ||
@@ -182,7 +217,7 @@ func validConfigKey(os *sys.OS, key string, value string) error {
 				return nil
 			}
 		}
-		return fmt.Errorf("security.syscalls.blacklist_compat isn't supported on this architecture")
+		return fmt.Errorf("%s isn't supported on this architecture", key)
 	}
 	return nil
 }
diff --git a/lxd/seccomp/seccomp.go b/lxd/seccomp/seccomp.go
index d72c97f45b..4d96eefe6e 100644
--- a/lxd/seccomp/seccomp.go
+++ b/lxd/seccomp/seccomp.go
@@ -389,6 +389,8 @@ func InstanceNeedsPolicy(c Instance) bool {
 	// Check for text keys
 	keys := []string{
 		"raw.seccomp",
+		"security.syscalls.allow",
+		"security.syscalls.deny",
 		"security.syscalls.whitelist",
 		"security.syscalls.blacklist",
 	}
@@ -402,6 +404,7 @@ func InstanceNeedsPolicy(c Instance) bool {
 
 	// Check for boolean keys that default to false
 	keys = []string{
+		"security.syscalls.deny_compat",
 		"security.syscalls.blacklist_compat",
 		"security.syscalls.intercept.mknod",
 		"security.syscalls.intercept.setxattr",
@@ -416,6 +419,7 @@ func InstanceNeedsPolicy(c Instance) bool {
 
 	// Check for boolean keys that default to true
 	keys = []string{
+		"security.syscalls.deny_default",
 		"security.syscalls.blacklist_default",
 	}
 
@@ -490,14 +494,25 @@ func seccompGetPolicyContent(s *state.State, c Instance) (string, error) {
 
 	// Policy header
 	policy := seccompHeader
-	whitelist := config["security.syscalls.whitelist"]
-	if whitelist != "" {
-		policy += "whitelist\n[all]\n"
-		policy += whitelist
+	allowlist := config["security.syscalls.allowlist"]
+	if allowlist != "" {
+		if s.OS.LXCFeatures["seccomp_allow_deny_syntax"] {
+			policy += "allowlist\n[all]\n"
+		} else {
+			policy += "whitelist\n[all]\n"
+		}
+		policy += allowlist
 	} else {
-		policy += "blacklist\n"
+		if s.OS.LXCFeatures["seccomp_allow_deny_syntax"] {
+			policy += "denylist\n[all]\n"
+		} else {
+			policy += "blacklist\n[all]\n"
+		}
 
-		defaultFlag, ok := config["security.syscalls.blacklist_default"]
+		defaultFlag, ok := config["security.syscalls.deny_default"]
+		if !ok {
+			defaultFlag, ok = config["security.syscalls.blacklist_default"]
+		}
 		if !ok || shared.IsTrue(defaultFlag) {
 			policy += defaultSeccompPolicy
 		}
@@ -531,12 +546,15 @@ func seccompGetPolicyContent(s *state.State, c Instance) (string, error) {
 		}
 	}
 
-	if whitelist != "" {
+	if allowlist != "" {
 		return policy, nil
 	}
 
-	// Additional blacklist entries
-	compat := config["security.syscalls.blacklist_compat"]
+	// Additional deny entries
+	compat, ok := config["security.syscalls.deny_compat"]
+	if !ok {
+		compat, ok = config["security.syscalls.blacklist_compat"]
+	}
 	if shared.IsTrue(compat) {
 		arch, err := osarch.ArchitectureName(c.Architecture())
 		if err != nil {
@@ -545,9 +563,12 @@ func seccompGetPolicyContent(s *state.State, c Instance) (string, error) {
 		policy += fmt.Sprintf(compatBlockingPolicy, arch)
 	}
 
-	blacklist := config["security.syscalls.blacklist"]
-	if blacklist != "" {
-		policy += blacklist
+	denylist, ok := config["security.syscalls.deny"]
+	if !ok {
+		denylist, ok = config["security.syscalls.blacklist"]
+	}
+	if denylist != "" {
+		policy += denylist
 	}
 
 	return policy, nil
diff --git a/scripts/bash/lxd-client b/scripts/bash/lxd-client
index 173bf03a10..37996d89b7 100644
--- a/scripts/bash/lxd-client
+++ b/scripts/bash/lxd-client
@@ -99,8 +99,9 @@ _have lxc && {
       security.idmap.size security.devlxd security.devlxd.images \
       security.nesting security.privileged security.protection.delete \
       security.protection.shift security.secureboot \
-      security.syscalls.blacklist \
-      security.syscalls.blacklist_compat security.syscalls.blacklist_default \
+      security.syscalls.allow \
+      security.syscalls.deny \
+      security.syscalls.deny_compat security.syscalls.deny_default \
       security.syscalls.intercept.mknod security.syscalls.intercept.mount \
       security.syscalls.intercept.mount.allowed \
       security.syscalls.intercept.mount.fuse \
diff --git a/shared/instance.go b/shared/instance.go
index 3bab51df3c..953981dbe1 100644
--- a/shared/instance.go
+++ b/shared/instance.go
@@ -322,6 +322,9 @@ var KnownInstanceConfigKeys = map[string]func(value string) error{
 
 	"security.secureboot": IsBool,
 
+	"security.syscalls.deny_default":            IsBool,
+	"security.syscalls.deny_compat":             IsBool,
+	"security.syscalls.deny":                    IsAny,
 	"security.syscalls.blacklist_default":       IsBool,
 	"security.syscalls.blacklist_compat":        IsBool,
 	"security.syscalls.blacklist":               IsAny,
@@ -331,6 +334,7 @@ var KnownInstanceConfigKeys = map[string]func(value string) error{
 	"security.syscalls.intercept.mount.fuse":    IsAny,
 	"security.syscalls.intercept.mount.shift":   IsBool,
 	"security.syscalls.intercept.setxattr":      IsBool,
+	"security.syscalls.allow":                   IsAny,
 	"security.syscalls.whitelist":               IsAny,
 
 	"snapshots.schedule": func(value string) error {
diff --git a/test/suites/basic.sh b/test/suites/basic.sh
index 95f7256327..f3afd39af2 100644
--- a/test/suites/basic.sh
+++ b/test/suites/basic.sh
@@ -447,7 +447,7 @@ test_basic_usage() {
   init=$(lxc info lxd-seccomp-test | grep Pid | cut -f2 -d" ")
   [ "$(grep Seccomp "/proc/${init}/status" | cut -f2)" -eq "2" ]
   lxc stop --force lxd-seccomp-test
-  lxc config set lxd-seccomp-test security.syscalls.blacklist_default false
+  lxc config set lxd-seccomp-test security.syscalls.deny_default false
   lxc start lxd-seccomp-test
   init=$(lxc info lxd-seccomp-test | grep Pid | cut -f2 -d" ")
   [ "$(grep Seccomp "/proc/${init}/status" | cut -f2)" -eq "0" ]


More information about the lxc-devel mailing list