diff --git a/config-linux.md b/config-linux.md index c71757494..2d8f2e49a 100644 --- a/config-linux.md +++ b/config-linux.md @@ -1040,6 +1040,51 @@ Example sending a single `seccompFd` file descriptor in the `SCM_RIGHTS` array: } ``` +## io_uring + +**`ioUring`** (object, OPTIONAL) restricts the [io_uring(7)][io_uring.7] operations that the container process can submit. +io_uring operations are not system calls, so [seccomp](#configLinuxSeccomp) cannot filter them. +Whether the io_uring system calls themselves are allowed is controlled by seccomp. + +* **`ops`** *(array of strings, REQUIRED)* - the io_uring operations that are allowed. + All other operations are denied, and an empty array denies all operations. + Whether an operation is allowed does not depend on its submission flags (`IOSQE_*`). + Values are names of the `IORING_OP_*` constants from ``, for example `IORING_OP_READ`. + The runtime MUST generate an error if it does not recognize a value. + The runtime MUST ignore a recognized value that the kernel does not support. +* **`socketFamilies`** *(array of strings, OPTIONAL)* - the address families that `IORING_OP_SOCKET` can create. + If this property is not set, any address family is allowed. + If it is set, it MUST NOT be empty; to deny all sockets, leave `IORING_OP_SOCKET` out of `ops`. + Values are names of the `AF_*` constants from ``, for example `AF_INET`. + The runtime MUST generate an error if it does not recognize a value. + The runtime MUST generate an error if this property is set and `ops` does not contain `IORING_OP_SOCKET`. + +The runtime MUST apply the restrictions before the container process is executed, so that they apply to the container process and all of its descendants. +If the runtime cannot apply the restrictions, it MUST generate an error. +Applying `ioUring` SHOULD NOT prevent the container process from registering further io_uring restrictions of its own. +The restrictions only apply to io_uring instances created after they are applied. +An io_uring instance passed into the container, for example with `SCM_RIGHTS`, is not restricted. + +### Example + +```json +"ioUring": { + "ops": [ + "IORING_OP_READ", + "IORING_OP_WRITE", + "IORING_OP_SEND", + "IORING_OP_RECV", + "IORING_OP_ACCEPT", + "IORING_OP_SOCKET" + ], + "socketFamilies": [ + "AF_UNIX", + "AF_INET", + "AF_INET6" + ] +} +``` + ## Rootfs Mount Propagation **`rootfsPropagation`** (string, OPTIONAL) sets the rootfs's mount propagation. @@ -1140,6 +1185,7 @@ subset of the available options. [full.4]: https://man7.org/linux/man-pages/man4/full.4.html [set_mempolicy.2]: https://man7.org/linux/man-pages/man2/set_mempolicy.2.html +[io_uring.7]: https://man7.org/linux/man-pages/man7/io_uring.7.html [mknod.1]: https://man7.org/linux/man-pages/man1/mknod.1.html [mknod.2]: https://man7.org/linux/man-pages/man2/mknod.2.html [namespaces.7_2]: https://man7.org/linux/man-pages/man7/namespaces.7.html diff --git a/features-linux.md b/features-linux.md index 3331266dd..9ec66ce75 100644 --- a/features-linux.md +++ b/features-linux.md @@ -165,6 +165,44 @@ Irrelevant to the kernel version of the host operating system. } ``` +## io_uring + +**`ioUring`** (object, OPTIONAL) represents the runtime's implementation status of io_uring restrictions. +Irrelevant to the kernel version of the host operating system. + +* **`enabled`** (bool, OPTIONAL) represents whether the runtime supports io_uring restrictions. +* **`ops`** (array of strings, OPTIONAL) The recognized names of the io_uring operations. + The runtime MUST recognize the elements in this array in the [`ops` property of the `linux.ioUring` object in `config.json`](config-linux.md#configLinuxIoUring). +* **`socketFamilies`** (array of strings, OPTIONAL) The recognized names of the address families. + The runtime MUST recognize the elements in this array in the [`socketFamilies` property of the `linux.ioUring` object in `config.json`](config-linux.md#configLinuxIoUring). + +### Example + +```json +"ioUring": { + "enabled": true, + "ops": [ + "IORING_OP_NOP", + "IORING_OP_READV", + "IORING_OP_WRITEV", + "IORING_OP_READ", + "IORING_OP_WRITE", + "IORING_OP_SEND", + "IORING_OP_RECV", + "IORING_OP_ACCEPT", + "IORING_OP_SOCKET" + ], + "socketFamilies": [ + "AF_UNIX", + "AF_INET", + "AF_INET6", + "AF_NETLINK", + "AF_PACKET", + "AF_VSOCK" + ] +} +``` + ## AppArmor **`apparmor`** (object, OPTIONAL) represents the runtime's implementation status of AppArmor. diff --git a/features.md b/features.md index 9c729591a..136feb940 100644 --- a/features.md +++ b/features.md @@ -348,6 +348,18 @@ Here is a full example for reference. "SECCOMP_FILTER_FLAG_LOG" ] }, + "ioUring": { + "enabled": true, + "ops": [ + "IORING_OP_READ", + "IORING_OP_WRITE" + ], + "socketFamilies": [ + "AF_UNIX", + "AF_INET", + "AF_INET6" + ] + }, "apparmor": { "enabled": true }, diff --git a/schema/config-linux.json b/schema/config-linux.json index 778561d89..613b14a00 100644 --- a/schema/config-linux.json +++ b/schema/config-linux.json @@ -250,6 +250,27 @@ "defaultAction" ] }, + "ioUring": { + "type": "object", + "properties": { + "ops": { + "type": "array", + "items": { + "$ref": "defs-linux.json#/definitions/IoUringOp" + } + }, + "socketFamilies": { + "type": "array", + "items": { + "$ref": "defs-linux.json#/definitions/SocketFamily" + }, + "minItems": 1 + } + }, + "required": [ + "ops" + ] + }, "sysctl": { "$ref": "defs.json#/definitions/mapStringString" }, diff --git a/schema/defs-linux.json b/schema/defs-linux.json index edc0a523c..a0e7545ac 100644 --- a/schema/defs-linux.json +++ b/schema/defs-linux.json @@ -266,6 +266,14 @@ "allow" ] }, + "IoUringOp": { + "type": "string", + "pattern": "^IORING_OP_[A-Z0-9_]+$" + }, + "SocketFamily": { + "type": "string", + "pattern": "^AF_[A-Z0-9_]+$" + }, "MemoryPolicyMode": { "type": "string", "enum": [ diff --git a/schema/features-linux.json b/schema/features-linux.json index fcf3df7d6..43204ea62 100644 --- a/schema/features-linux.json +++ b/schema/features-linux.json @@ -74,6 +74,26 @@ } } }, + "ioUring": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "ops": { + "type": "array", + "items": { + "$ref": "defs-linux.json#/definitions/IoUringOp" + } + }, + "socketFamilies": { + "type": "array", + "items": { + "$ref": "defs-linux.json#/definitions/SocketFamily" + } + } + } + }, "apparmor": { "type": "object", "properties": { diff --git a/schema/test/config/bad/linux-io-uring-empty-families.json b/schema/test/config/bad/linux-io-uring-empty-families.json new file mode 100644 index 000000000..789638c36 --- /dev/null +++ b/schema/test/config/bad/linux-io-uring-empty-families.json @@ -0,0 +1,14 @@ +{ + "ociVersion": "1.0.0", + "root": { + "path": "rootfs" + }, + "linux": { + "ioUring": { + "ops": [ + "IORING_OP_SOCKET" + ], + "socketFamilies": [] + } + } +} diff --git a/schema/test/config/bad/linux-io-uring-invalid-op.json b/schema/test/config/bad/linux-io-uring-invalid-op.json new file mode 100644 index 000000000..c79455729 --- /dev/null +++ b/schema/test/config/bad/linux-io-uring-invalid-op.json @@ -0,0 +1,13 @@ +{ + "ociVersion": "1.0.0", + "root": { + "path": "rootfs" + }, + "linux": { + "ioUring": { + "ops": [ + "read" + ] + } + } +} diff --git a/schema/test/config/bad/linux-io-uring.json b/schema/test/config/bad/linux-io-uring.json new file mode 100644 index 000000000..2e63cfdd4 --- /dev/null +++ b/schema/test/config/bad/linux-io-uring.json @@ -0,0 +1,13 @@ +{ + "ociVersion": "1.0.0", + "root": { + "path": "rootfs" + }, + "linux": { + "ioUring": { + "socketFamilies": [ + "AF_INET" + ] + } + } +} diff --git a/schema/test/config/good/linux-io-uring.json b/schema/test/config/good/linux-io-uring.json new file mode 100644 index 000000000..18817ab4e --- /dev/null +++ b/schema/test/config/good/linux-io-uring.json @@ -0,0 +1,19 @@ +{ + "ociVersion": "1.0.0", + "root": { + "path": "rootfs" + }, + "linux": { + "ioUring": { + "ops": [ + "IORING_OP_READ", + "IORING_OP_WRITE", + "IORING_OP_SOCKET" + ], + "socketFamilies": [ + "AF_UNIX", + "AF_INET6" + ] + } + } +} diff --git a/specs-go/config.go b/specs-go/config.go index 711eb9e17..18e04fbcf 100644 --- a/specs-go/config.go +++ b/specs-go/config.go @@ -242,6 +242,8 @@ type Linux struct { NetDevices map[string]LinuxNetDevice `json:"netDevices,omitempty"` // Seccomp specifies the seccomp security settings for the container. Seccomp *LinuxSeccomp `json:"seccomp,omitempty"` + // IOUring restricts the io_uring operations available to the container. + IOUring *LinuxIOUring `json:"ioUring,omitempty"` // RootfsPropagation is the rootfs mount propagation mode for the container. RootfsPropagation string `json:"rootfsPropagation,omitempty"` // MaskedPaths masks over the provided paths inside the container. @@ -892,6 +894,17 @@ type LinuxIntelRdt struct { EnableMonitoring bool `json:"enableMonitoring,omitempty"` } +// LinuxIOUring restricts the io_uring operations available to the container. +type LinuxIOUring struct { + // Ops is the list of allowed io_uring operations, e.g., "IORING_OP_READ". + // All other operations are denied. + Ops []string `json:"ops"` + // SocketFamilies is the list of address families that IORING_OP_SOCKET + // can create, e.g., "AF_INET". Nil or empty means any address family; + // to deny all sockets, leave IORING_OP_SOCKET out of Ops. + SocketFamilies []string `json:"socketFamilies,omitempty"` +} + // LinuxMemoryPolicy represents input for the set_mempolicy syscall. type LinuxMemoryPolicy struct { // Mode for the set_mempolicy syscall. diff --git a/specs-go/features/features.go b/specs-go/features/features.go index 7b4c40640..d7bf626f4 100644 --- a/specs-go/features/features.go +++ b/specs-go/features/features.go @@ -44,6 +44,7 @@ type Linux struct { Cgroup *Cgroup `json:"cgroup,omitempty"` Seccomp *Seccomp `json:"seccomp,omitempty"` + IOUring *IOUring `json:"ioUring,omitempty"` Apparmor *Apparmor `json:"apparmor,omitempty"` Selinux *Selinux `json:"selinux,omitempty"` IntelRdt *IntelRdt `json:"intelRdt,omitempty"` @@ -109,6 +110,21 @@ type Seccomp struct { SupportedFlags []string `json:"supportedFlags,omitempty"` } +// IOUring represents the "ioUring" field. +type IOUring struct { + // Enabled is true if io_uring restrictions support is compiled in. + // Nil value means "unknown", not "false". + Enabled *bool `json:"enabled,omitempty"` + + // Ops is the list of the recognized io_uring operations, e.g., "IORING_OP_READ". + // Nil value means "unknown", not "no support for any operation". + Ops []string `json:"ops,omitempty"` + + // SocketFamilies is the list of the recognized address families, e.g., "AF_INET". + // Nil value means "unknown", not "no support for any address family". + SocketFamilies []string `json:"socketFamilies,omitempty"` +} + // Apparmor represents the "apparmor" field. type Apparmor struct { // Enabled is true if AppArmor support is compiled in.