containerd CRI plugin: Host memory exhaustion through ExecSync
Description
containerd is an open source container runtime. A bug was found in the containerd's CRI implementation where programs inside a container can cause the containerd daemon to consume memory without bound during invocation of the ExecSync API. This can cause containerd to consume all available memory on the computer, denying service to other legitimate workloads. Kubernetes and crictl can both be configured to use containerd's CRI implementation; ExecSync may be used when running probes or when executing processes via an "exec" facility. This bug has been fixed in containerd 1.6.6 and 1.5.13. Users should update to these versions to resolve the issue. Users unable to upgrade should ensure that only trusted images and commands are used.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
github.com/containerd/containerdGo | < 1.5.13 | 1.5.13 |
github.com/containerd/containerdGo | >= 1.6.0, < 1.6.6 | 1.6.6 |
Affected products
1- Range: < 1.5.13
Patches
1c1bcabb45419Merge pull request from GHSA-5ffw-gxpp-mxpf
2 files changed · +95 −2
pkg/cri/server/container_execsync.go+43 −2 modified@@ -38,14 +38,55 @@ import ( cioutil "github.com/containerd/containerd/pkg/ioutil" ) +type cappedWriter struct { + w io.WriteCloser + remain int +} + +func (cw *cappedWriter) Write(p []byte) (int, error) { + if cw.remain <= 0 { + return len(p), nil + } + + end := cw.remain + if end > len(p) { + end = len(p) + } + written, err := cw.w.Write(p[0:end]) + cw.remain -= written + + if err != nil { + return written, err + } + return len(p), nil +} + +func (cw *cappedWriter) Close() error { + return cw.w.Close() +} + +func (cw *cappedWriter) isFull() bool { + return cw.remain <= 0 +} + // ExecSync executes a command in the container, and returns the stdout output. // If command exits with a non-zero exit code, an error is returned. func (c *criService) ExecSync(ctx context.Context, r *runtime.ExecSyncRequest) (*runtime.ExecSyncResponse, error) { + const maxStreamSize = 1024 * 1024 * 16 + var stdout, stderr bytes.Buffer + + // cappedWriter truncates the output. In that case, the size of + // the ExecSyncResponse will hit the CRI plugin's gRPC response limit. + // Thus the callers outside of the containerd process (e.g. Kubelet) never see + // the truncated output. + cout := &cappedWriter{w: cioutil.NewNopWriteCloser(&stdout), remain: maxStreamSize} + cerr := &cappedWriter{w: cioutil.NewNopWriteCloser(&stderr), remain: maxStreamSize} + exitCode, err := c.execInContainer(ctx, r.GetContainerId(), execOptions{ cmd: r.GetCmd(), - stdout: cioutil.NewNopWriteCloser(&stdout), - stderr: cioutil.NewNopWriteCloser(&stderr), + stdout: cout, + stderr: cerr, timeout: time.Duration(r.GetTimeout()) * time.Second, }) if err != nil {
pkg/cri/server/container_execsync_test.go+52 −0 added@@ -0,0 +1,52 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "bytes" + "testing" + + cioutil "github.com/containerd/containerd/pkg/ioutil" + "github.com/stretchr/testify/assert" +) + +func TestCWWrite(t *testing.T) { + var buf bytes.Buffer + cw := &cappedWriter{w: cioutil.NewNopWriteCloser(&buf), remain: 10} + + n, err := cw.Write([]byte("hello")) + assert.NoError(t, err) + assert.Equal(t, 5, n) + + n, err = cw.Write([]byte("helloworld")) + assert.NoError(t, err, "no errors even it hits the cap") + assert.Equal(t, 10, n, "no indication of partial write") + assert.True(t, cw.isFull()) + assert.Equal(t, []byte("hellohello"), buf.Bytes(), "the underlying writer is capped") + + _, err = cw.Write([]byte("world")) + assert.NoError(t, err) + assert.True(t, cw.isFull()) + assert.Equal(t, []byte("hellohello"), buf.Bytes(), "the underlying writer is capped") +} + +func TestCWClose(t *testing.T) { + var buf bytes.Buffer + cw := &cappedWriter{w: cioutil.NewNopWriteCloser(&buf), remain: 5} + err := cw.Close() + assert.NoError(t, err) +}
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
13- github.com/advisories/GHSA-5ffw-gxpp-mxpfghsaADVISORY
- lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/REOZCUAPCA7NFDWYBDYX6EYXWLHABKBO/mitrevendor-advisory
- lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/WSIGDBHAB3I75JBJNGWEPBTJPS2FOVHD/mitrevendor-advisory
- nvd.nist.gov/vuln/detail/CVE-2022-31030ghsaADVISORY
- security.gentoo.org/glsa/202401-31ghsavendor-advisoryWEB
- www.debian.org/security/2022/dsa-5162ghsavendor-advisoryWEB
- www.openwall.com/lists/oss-security/2022/06/07/1ghsamailing-listWEB
- github.com/containerd/containerd/commit/c1bcabb4541930f643aa36a2b38655e131346382ghsaWEB
- github.com/containerd/containerd/security/advisories/GHSA-5ffw-gxpp-mxpfghsaWEB
- lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/REOZCUAPCA7NFDWYBDYX6EYXWLHABKBOghsaWEB
- lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/WSIGDBHAB3I75JBJNGWEPBTJPS2FOVHDghsaWEB
- lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/REOZCUAPCA7NFDWYBDYX6EYXWLHABKBOghsaWEB
- lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/WSIGDBHAB3I75JBJNGWEPBTJPS2FOVHDghsaWEB
News mentions
0No linked articles in our index yet.