VYPR
Moderate severityNVD Advisory· Published Jun 6, 2022· Updated Aug 3, 2024

containerd CRI plugin: Host memory exhaustion through ExecSync

CVE-2022-31030

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.

PackageAffected versionsPatched versions
github.com/containerd/containerdGo
< 1.5.131.5.13
github.com/containerd/containerdGo
>= 1.6.0, < 1.6.61.6.6

Affected products

1

Patches

1
c1bcabb45419

Merge pull request from GHSA-5ffw-gxpp-mxpf

https://github.com/containerd/containerdDerek McGowanJun 6, 2022via ghsa
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

News mentions

0

No linked articles in our index yet.