Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Carry #1111: specs-go/config: add Landlock LSM support #1241

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 121 additions & 1 deletion config.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this PR should be carefully updated following the latest advances of landlock (rather than simply carried) as some of the spec proposals might be stale now. Pls see https://docs.kernel.org/userspace-api/landlock.html and https://github.com/landlock-lsm/go-landlock for details.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you got time to continue this PR or I can continue carry(

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pls go ahead updating this PR. I'll need some time to follow up and dive into the updates of landlock (even for review).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if the runtime doesn't know this field? I guess in runc it will be completely ignored, right? In that case, I think we at least need to expose landlock support via the features command too.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the runtime will ignore the field. I think it's not necessary to add feature command like other optional features.

Copy link
Member

@rata rata Mar 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Zheaoli why not? This is a security feature, I can see use cases where upper layers want to enforce this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

friendly ping?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for replying late. I misunderstand something before. I think it's necessary to export the feature we support for landlock in features command

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This wasn't done, right?

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.

### <a name="configUser" />User

Expand Down Expand Up @@ -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": [
Expand Down Expand Up @@ -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
Expand Down
14 changes: 14 additions & 0 deletions schema/config-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
},
Expand Down
106 changes: 106 additions & 0 deletions schema/defs.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@
"minimum": 0,
"maximum": 100
},
"port": {
"type": "integer",
"minimum": 0,
"maximum": 65535
},
"mapStringString": {
"type": "object",
"patternProperties": {
Expand Down Expand Up @@ -75,6 +80,12 @@
"type": "string"
}
},
"ArrayOfPorts": {
"type": "array",
"items": {
"$ref": "#/definitions/port"
}
},
"FilePath": {
"type": "string"
},
Expand Down Expand Up @@ -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"
}
}
}
}
}
78 changes: 78 additions & 0 deletions specs-go/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Loading