Skip to content

Unbounded memory allocation (OOM) during OCI hook execution #797

Description

@abhaygoudannavar

Description

In pkg/unikontainers/unikontainers.go, the executeHook function runs OCI hooks (like prestart, poststart, etc.) and captures their standard output and standard error using Go's bytes.Buffer:

// unikontainers.go:1251
func executeHook(hook specs.Hook, state []byte) error {
	var stdout, stderr bytes.Buffer
    // ...
	cmd := exec.CommandContext(ctx, hook.Path, args...)
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr
	err := cmd.Run()
    // ...
}

A bytes.Buffer grows automatically to accommodate all incoming data. If an OCI hook outputs a massive amount of data (e.g., streaming gigabytes of logs or just entering an infinite loop that prints text), the bytes.Buffer will grow without limit.This will consume all available memory on the node, eventually causing the Linux OOM (Out-Of-Memory) killer to terminate the urunc / containerd-shim process.

  • Denial of Service (DoS): A malicious container image with a custom hook, or even a buggy legitimate hook, can trivially crash the runtime and potentially destabilize the entire Kubernetes node by exhausting memory.

System info

  • Urunc version: v0.7.0 (current main)
  • Arch: amd64
  • VMM: All (bug is VMM-independent)
  • Unikernel: All (bug is unikernel-independent)

Steps to reproduce

  1. Create a simple executable script (e.g., spam.sh)
#!/bin/sh
yes "spamming stdout forever to crash urunc"
  1. Configure a container with this script as a prestart OCI hook.
  2. Run urunc create.
  3. The urunc-reexec process will rapidly consume gigabytes of RAM until the Linux OOM killer terminates it.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions