diff --git a/config.md b/config.md index 704bbaa2f..946482551 100644 --- a/config.md +++ b/config.md @@ -352,6 +352,52 @@ For Linux-based systems, the `process` object supports the following process-spe for `initial`. If omitted or empty, runtime SHOULD NOT change process' CPU affinity after the process is moved to container's cgroup, and the final affinity is determined by the Linux kernel. +* **`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: + + * **`handledAccess`** (object, OPTIONAL) specifies the access rights that will be restricted by the ruleset. + The `handledAccess` 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. + * **`handledAccessNetwork`** (array of strings, OPTIONAL) is an array of NETWORK typed actions that are handled by a ruleset. (The NETWORK typed actions are available when the ABI version >= 4. The behavior when the ABI version is less than 4 will depend on the **`enableBestEffort`**) + * **`rules`** (object, OPTIONAL) specifies the security policies (i.e., actions allowed on objects) to be enforced. + 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. execute + 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. + * **`networkPort`** (array of objects, OPTIONAL) is an array of the network socket 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. + * **`enableBestEffort`** (bool, OPTIONAL) the `enableBestEffort` 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 `true`, i.e., following a best-effort security approach. ### User @@ -397,6 +443,79 @@ _Note: symbolic name for uid and gid, such as uname and gname respectively, are "class": "IOPRIO_CLASS_IDLE", "priority": 4 }, + "landlock": { + "handledAccess": { + "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" + ], + "handledAccessNetwork": [ + "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" + ] + } + ], + "networkPort": [ + { + "allowedAccess": [ + "bind", + "connect" + ], + "ports": [ + 80, + 443 + ] + } + ] + }, + "enableBestEffort": true + }, "noNewPrivileges": true, "capabilities": { "bounding": [ @@ -1151,7 +1270,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]:https://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]: https://pubs.opengroup.org/onlinepubs/009695399/functions/umask.html diff --git a/schema/config-schema.json b/schema/config-schema.json index 5124def5f..9d00595e5 100644 --- a/schema/config-schema.json +++ b/schema/config-schema.json @@ -163,6 +163,20 @@ } } }, + "landlock": { + "type": "object", + "properties": { + "handledAccess": { + "$ref": "defs.json#/definitions/LandlockHandledAccess" + }, + "rules": { + "$ref": "defs.json#/definitions/LandlockRules" + }, + "enableBestEffort": { + "type": "boolean" + } + } + }, "noNewPrivileges": { "type": "boolean" }, diff --git a/schema/defs.json b/schema/defs.json index a0bf846a1..181c9b07d 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,101 @@ }, "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" + } + }, + "LandlockHandledAccess": { + "type": "object", + "properties": { + "handledAccessFS": { + "$ref": "#/definitions/ArrayOfLandlockFSActions" + }, + "handledAccessNetwork": { + "$ref": "#/definitions/ArrayOfLandlockNetworkActions" + } + } + }, + "LandlockRulePathBeneath": { + "type": "object", + "properties": { + "allowedAccess": { + "$ref": "#/definitions/ArrayOfLandlockFSActions" + }, + "paths": { + "$ref": "#/definitions/ArrayOfStrings" + } + } + }, + "LandlockRuleNetworkPort": { + "type": "object", + "properties": { + "allowedAccess": { + "$ref": "#/definitions/ArrayOfLandlockNetworkActions" + }, + "ports": { + "$ref": "#/definitions/ArrayOfPorts" + } + } + }, + "ArrayOfLandlockRulePathBeneaths": { + "type": "array", + "items": { + "$ref": "#/definitions/LandlockRulePathBeneath" + } + }, + "ArrayOfLandlockRuleNetworkPorts": { + "type": "array", + "items": { + "$ref": "#/definitions/LandlockRuleNetworkPort" + } + }, + "LandlockRules": { + "type": "object", + "properties": { + "pathBeneath": { + "$ref": "#/definitions/ArrayOfLandlockRulePathBeneaths" + }, + "networkPort": { + "$ref": "#/definitions/ArrayOfLandlockRuleNetworkPorts" + } + } } } } diff --git a/specs-go/config.go b/specs-go/config.go index f7a78d51b..abb9c0490 100644 --- a/specs-go/config.go +++ b/specs-go/config.go @@ -96,8 +96,86 @@ type Process struct { IOPriority *LinuxIOPriority `json:"ioPriority,omitempty" platform:"linux"` // ExecCPUAffinity specifies CPU affinity for exec processes. ExecCPUAffinity *CPUAffinity `json:"execCPUAffinity,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 { + // HandledAccess specifies the access rights that will be restricted by the ruleset. + HandledAccess *LandlockHandledAccess `json:"handledAccess,omitempty" platform:"linux"` + // Rules are the security policies (i.e., actions allowed on objects) to be enforced. + Rules *LandlockRules `json:"rules,omitempty" platform:"linux"` + // EnableBestEffort 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. + EnableBestEffort bool `json:"enableBestEffort,omitempty" platform:"linux"` +} + +// LandlockHandledAccess specifies the access rights that will be restricted by the ruleset. +type LandlockHandledAccess struct { + // HandledAccessFS specifies filesystem actions that will be restricted unless explicitly allowed by rules. + HandledAccessFS []LandlockFSAction `json:"handledAccessFS,omitempty" platform:"linux"` + // HandledAccessNetwork specifies network actions that will be restricted unless explicitly allowed by rules. + HandledAccessNetwork []LandlockNetworkAction `json:"handledAccessNetwork,omitempty" platform:"linux"` +} + +// LandlockRules represents the security policies (i.e., actions allowed on objects). +type LandlockRules struct { + // PathBeneath specifies file-hierarchy access rules. + PathBeneath []LandlockRulePathBeneath `json:"pathBeneath,omitempty" platform:"linux"` + // NetworkPort specifies network socket access rules. + NetworkPort []LandlockRuleNetworkPort `json:"networkPort,omitempty" platform:"linux"` +} + +// LandlockRulePathBeneath grants filesystem access rights to hierarchies under specified paths. +type LandlockRulePathBeneath struct { + // AllowedAccess lists 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"` +} + +// LandlockRuleNetworkPort grants network access rights to specified ports. +type LandlockRuleNetworkPort struct { + // AllowedAccess lists 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 specifies filesystem actions that can be restricted by Landlock. +type LandlockFSAction string + +// 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" +) + +// LandlockNetworkAction specifies network actions that can be restricted by Landlock. +type LandlockNetworkAction string + +const ( + LLNetworkActConnect LandlockNetworkAction = "connect" + LLNetworkActBind LandlockNetworkAction = "bind" +) + // LinuxCapabilities specifies the list of allowed capabilities that are kept for a process. // https://man7.org/linux/man-pages/man7/capabilities.7.html type LinuxCapabilities struct {