diff --git a/config.md b/config.md index a1b39adf4..870168506 100644 --- a/config.md +++ b/config.md @@ -340,6 +340,52 @@ For Linux-based systems, the `process` object supports the following process-spe * **`class`** (string, REQUIRED) specifies the I/O scheduling class. Possible values are `IOPRIO_CLASS_RT`, `IOPRIO_CLASS_BE`, and `IOPRIO_CLASS_IDLE`. * **`priority`** (int, REQUIRED) specifies the priority level within the class. The value should be an integer ranging from 0 (highest) to 7 (lowest). +* **`landlock`** (object, OPTIONAL) specifies the Landlock unprivileged access control settings for the container process. + Note that `noNewPrivileges` must be set to true to use this feature. + For more information about Landlock, see [Landlock documentation][landlock]. + `landlock` contains the following properties: + + * **`ruleset`** (object, OPTIONAL) the `ruleset` field identifies a set of rules (i.e., actions on objects) that need to be handled (i.e., restricted). + The `ruleset` currently contains the following types: + * **`handledAccessFS`** (array of strings, OPTIONAL) is an array of FS typed actions that are handled by a ruleset. + If no rule explicitly allow them, they should then be forbidden. + * **`handledAssessNetwork`** (array of strings, OPTIONAL) is an array of NETWORK typed actions that are handled by a ruleset. (The NETWORK typed actions are avaliable when the ABI version >= 4. the behavior of the NETWORK typed actions is not used when the ABI version is less than 4 will depend on the **`disableBestEffort`**) + * **`rules`** (object, OPTIONAL) the `rules` field specifies the security policies (i.e., actions allowed on objects) to be added to an existing ruleset. + The `rules` currently contains the following types: + * **`pathBeneath`** (array of objects, OPTIONAL) is an array of the file-hierarchy typed rules. + Entries in the array contain the following properties: + * **`allowedAccess`** (array of strings, OPTIONAL) is an array of FS typed actions that are allowed by a rule. The actions are grouped by the ABI version in the following description: + 1. ABI version >= 1: + 1. exectute + 2. write_file + 3. read_file + 4. read_dir + 5. remove_dir + 6. remove_file + 7. make_char + 8. make_dir + 9. make_reg + 10. make_sock + 11. make_fifo + 12. make_block + 13. make_sym + 2. ABI version >= 2: + 1. refer + 3. ABI version >= 3: + 1. truncate + * **`paths`** (array of strings, OPTIONAL) is an array of files or parent directories of the file hierarchies to restrict. + * **`portBeneath`** (array of objects, OPTIONAL) is an array of the network-hierarchy typed rules. + Entries in the array contain the following properties: + * **`allowedAccess`** (array of strings, OPTIONAL) is an array of NETWORK typed actions that are allowed by a rule. The actions are grouped by the ABI version in the following description: + 1. ABI version >= 4: + 1. bind + 2. connect + * **`ports`** (array of strings, OPTIONAL) is an array of network ports to restrict. + * **`disableBestEffort`** (bool, OPTIONAL) the `disableBestEffort` field disables the best-effort security approach for Landlock access rights. + This is for conditions when the Landlock access rights explicitly configured by the container are not supported or available in the running kernel. + If the best-effort security approach is enabled (`false`), the runtime SHOULD enforce the strongest rules configured up to the current kernel support, and only be [logged as a warning](runtime.md#warnings) for those not supported. + If disabled (`true`), the runtime MUST [generate an error](runtime.md#errors) if one or more rules specified by the container is not supported. + Default is `false`, i.e., following a best-effort security approach. ### User @@ -385,6 +431,79 @@ _Note: symbolic name for uid and gid, such as uname and gname respectively, are "class": "IOPRIO_CLASS_IDLE", "priority": 4 }, + "landlock": { + "ruleset": { + "handledAccessFS": [ + "execute", + "write_file", + "read_file", + "read_dir", + "remove_dir", + "remove_file", + "make_char", + "make_dir", + "make_reg", + "make_sock", + "make_fifo", + "make_block", + "make_sym", + "refer", + "truncate" + ], + "handledAssessNetwork": [ + "bind", + "connect" + ] + }, + "rules": { + "pathBeneath": [ + { + "allowedAccess": [ + "execute", + "read_file", + "read_dir" + ], + "paths": [ + "/usr", + "/bin" + ] + }, + { + "allowedAccess": [ + "execute", + "write_file", + "read_file", + "read_dir", + "remove_dir", + "remove_file", + "make_char", + "make_dir", + "make_reg", + "make_sock", + "make_fifo", + "make_block", + "make_sym" + ], + "paths": [ + "/tmp" + ] + } + ], + "portBeneath": [ + { + "allowedAccess": [ + "bind", + "connect" + ], + "ports": [ + 80, + 443 + ] + } + ] + }, + "disableBestEffort": false + }, "noNewPrivileges": true, "capabilities": { "bounding": [ @@ -1135,7 +1254,8 @@ Here is a full example `config.json` for reference. [apparmor]: https://wiki.ubuntu.com/AppArmor [cgroup-v1-memory_2]: https://www.kernel.org/doc/Documentation/cgroup-v1/memory.txt -[selinux]:http://selinuxproject.org/page/Main_Page +[selinux]: http://selinuxproject.org/page/Main_Page +[landlock]: https://landlock.io [no-new-privs]: https://www.kernel.org/doc/Documentation/prctl/no_new_privs.txt [proc_2]: https://www.kernel.org/doc/Documentation/filesystems/proc.txt [umask.2]: http://pubs.opengroup.org/onlinepubs/009695399/functions/umask.html diff --git a/schema/config-schema.json b/schema/config-schema.json index 8f2bff772..04ff84160 100644 --- a/schema/config-schema.json +++ b/schema/config-schema.json @@ -163,6 +163,20 @@ } } }, + "landlock": { + "type": "object", + "properties": { + "ruleset": { + "$ref": "defs.json#/definitions/LandlockRuleset" + }, + "rules": { + "$ref": "defs.json#/definitions/LandlockRules" + }, + "disableBestEffort": { + "type": "boolean" + } + } + }, "noNewPrivileges": { "type": "boolean" }, diff --git a/schema/defs.json b/schema/defs.json index a0bf846a1..1f008c608 100644 --- a/schema/defs.json +++ b/schema/defs.json @@ -46,6 +46,11 @@ "minimum": 0, "maximum": 100 }, + "port": { + "type": "integer", + "minimum": 0, + "maximum": 65535 + }, "mapStringString": { "type": "object", "patternProperties": { @@ -75,6 +80,12 @@ "type": "string" } }, + "ArrayOfPorts":{ + "type": "array", + "items": { + "$ref": "#/definitions/port" + } + }, "FilePath": { "type": "string" }, @@ -165,6 +176,98 @@ }, "annotations": { "$ref": "#/definitions/mapStringString" + }, + "LandlockFSAction": { + "type": "string", + "enum": [ + "execute", + "write_file", + "read_file", + "read_dir", + "remove_dir", + "remove_file", + "make_char", + "make_dir", + "make_reg", + "make_sock", + "make_fifo", + "make_block", + "make_sym", + "refer", + "truncate" + ] + }, + "LandlockNetworkAction": { + "type": "string", + "enum": [ + "bind", + "connect" + ] + }, + "ArrayOfLandlockFSActions": { + "type": "array", + "items": { + "$ref": "#/definitions/LandlockFSAction" + } + }, + "ArrayOfLandlockNetworkActions": { + "type": "array", + "items": { + "$ref": "#/definitions/LandlockNetworkAction" + } + }, + "LandlockRuleset": { + "type": "object", + "properties": { + "handledAccessFS": { + "$ref": "#/definitions/ArrayOfLandlockFSActions" + }, + "handledAssessNetwork": { + "$ref": "#/definitions/ArrayOfLandlockNetworkActions" + } + } + }, + "LandlockRulePathBeneath": { + "type": "object", + "properties": { + "allowedAccess": { + "$ref": "#/definitions/ArrayOfLandlockFSActions" + }, + "paths": { + "$ref": "#/definitions/ArrayOfStrings" + } + } + }, + "LandlockRulePortBeneath": { + "type": "object", + "properties": { + "allowedAccess": { + "$ref": "#/definitions/ArrayOfLandlockNetworkActions" + }, + "paths": { + "$ref": "#/definitions/ArrayOfPorts" + } + } + }, + "ArrayOfLandlockRulePathBeneaths": { + "type": "array", + "items": { + "$ref": "#/definitions/LandlockRulePathBeneath" + } + }, + "ArrayOfLandlockRulePortBeneaths": { + "type": "array", + "items": { + "$ref": "#/definitions/LandlockRulePortBeneath" + } + }, + "LandlockRules": { + "type": "object", + "properties": { + "pathBeneath": { + "$ref": "#/definitions/ArrayOfLandlockRulePathBeneaths" + } + } } } } diff --git a/specs-go/config.go b/specs-go/config.go index d1236ba72..98a4f7ed3 100644 --- a/specs-go/config.go +++ b/specs-go/config.go @@ -94,7 +94,86 @@ type Process struct { SelinuxLabel string `json:"selinuxLabel,omitempty" platform:"linux"` // IOPriority contains the I/O priority settings for the cgroup. IOPriority *LinuxIOPriority `json:"ioPriority,omitempty" platform:"linux"` -} + // Landlock specifies the Landlock unprivileged access control settings for the container process. + // `noNewPrivileges` must be enabled to use Landlock. + Landlock *Landlock `json:"landlock,omitempty" platform:"linux"` +} + +// Landlock specifies the Landlock unprivileged access control settings for the container process. +type Landlock struct { + // Ruleset identifies a set of rules (i.e., actions on objects) that need to be handled. + Ruleset *LandlockRuleset `json:"ruleset,omitempty" platform:"linux"` + // Rules are the security policies (i.e., actions allowed on objects) to be added to an existing ruleset. + Rules *LandlockRules `json:"rules,omitempty" platform:"linux"` + // DisableBestEffort disables the best-effort security approach for Landlock access rights. + // This is for conditions when the Landlock access rights explicitly configured by the container are not + // supported or available in the running kernel. + // Default is false, i.e., following a best-effort security approach. + DisableBestEffort bool `json:"disableBestEffort,omitempty" platform:"linux"` +} + +// LandlockRuleset identifies a set of rules (i.e., actions on objects) that need to be handled. +type LandlockRuleset struct { + // HandledAccessFS is a list of actions that is handled by this ruleset and should then be + // forbidden if no rule explicitly allow them. + HandledAccessFS []LandlockFSAction `json:"handledAccessFS,omitempty" platform:"linux"` + // HandledAccessNetwork is a list of actions that is handled by this ruleset and should then be + // forbidden if no rule explicitly allow them. + HandledAccessNetwork []LandlockNetworkAction `json:"handledAccessNetwork,omitempty" platform:"linux"` +} + +// LandlockRules represents the security policies (i.e., actions allowed on objects). +type LandlockRules struct { + // PathBeneath specifies the file-hierarchy typed rules. + PathBeneath []LandlockRulePathBeneath `json:"pathBeneath,omitempty" platform:"linux"` + // PortBeneath specifies the network-socket typed rules. + PortBeneath []LandlockRulePortBeneath `json:"portBeneath,omitempty" platform:"linux"` +} + +// LandlockRulePathBeneath defines the file-hierarchy typed rule that grants the access rights specified by +// `AllowedAccess` to the file hierarchies under the given `Paths`. +type LandlockRulePathBeneath struct { + // AllowedAccess contains a list of allowed filesystem actions for the file hierarchies. + AllowedAccess []LandlockFSAction `json:"allowedAccess,omitempty" platform:"linux"` + // Paths are the files or parent directories of the file hierarchies to restrict. + Paths []string `json:"paths,omitempty" platform:"linux"` +} + +type LandlockRulePortBeneath struct { + // AllowedAccess contains a list of allowed network actions for the network sockets. + AllowedAccess []LandlockNetworkAction `json:"allowedAccess,omitempty" platform:"linux"` + // Ports are the network ports to restrict. + Ports []string `json:"ports,omitempty" platform:"linux"` +} + +// LandlockFSAction used to specify the FS actions that are handled by a ruleset or allowed by a rule. +type LandlockFSAction string + +// Define actions on files and directories that Landlock can restrict a sandboxed process to. +const ( + LLFSActExecute LandlockFSAction = "execute" + LLFSActWriteFile LandlockFSAction = "write_file" + LLFSActReadFile LandlockFSAction = "read_file" + LLFSActReadDir LandlockFSAction = "read_dir" + LLFSActRemoveDir LandlockFSAction = "remove_dir" + LLFSActRemoveFile LandlockFSAction = "remove_file" + LLFSActMakeChar LandlockFSAction = "make_char" + LLFSActMakeDir LandlockFSAction = "make_dir" + LLFSActMakeReg LandlockFSAction = "make_reg" + LLFSActMakeSock LandlockFSAction = "make_sock" + LLFSActMakeFifo LandlockFSAction = "make_fifo" + LLFSActMakeBlock LandlockFSAction = "make_block" + LLFSActMakeSym LandlockFSAction = "make_sym" + LLFSActRefer LandlockFSAction = "refer" + LLFSActTruncate LandlockFSAction = "truncate" +) + +type LandlockNetworkAction string + +const ( + LLNetworkActConnect LandlockNetworkAction = "connect" + LLNetworkActBind LandlockNetworkAction = "bind" +) // LinuxCapabilities specifies the list of allowed capabilities that are kept for a process. // http://man7.org/linux/man-pages/man7/capabilities.7.html