You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Is your feature request related to a problem? Please describe:
CDI currently uses prlimit(RLIMIT_AS) to limit the virtual address space of qemu-img subprocesses. The limit originates from an OpenStack Nova recommendation (1 GiB) and was intended to prevent malicious disk images from causing qemu-img to allocate arbitrary amounts of memory.
However, RLIMIT_AS limits virtual address space, not physical (RSS) memory. This is a problematic distinction that has caused real issues:
Incompatibility with Go runtime — The Go runtime reserves large virtual address spaces via mmap (for GC arenas, span management, etc.) that never translate to physical memory usage. Setting RLIMIT_AS on Go programs causes sporadic crashes. This is confirmed upstream as expected behavior, not a bug. The Go team effectively considers RLIMIT_AS incompatible with Go programs. This has caused s390x unit test failures with SIGSEGV (Prlimit Unit Test fails on s390x #3341), sporadic amd64 unit test failures with runtime: cannot allocate memory, and architecture-dependent flakiness due to varying mmap layouts.
Redundant in a containerized environment — CDI runs in Kubernetes pods with container-level resource limits. The container runtime enforces memory limits via cgroups (which limit RSS/physical memory), providing a more robust and appropriate mechanism than RLIMIT_AS. The address space limit adds no meaningful protection on top of cgroup constraints.
Limited practical scope — The address space limit is currently only applied to qemu-img info calls (qemu.go:222). All other qemu-img operations (convert, resize, create, rebase, commit) already pass nil limits. The CPU time limit + context timeout already protect against hung processes.
The original motivation no longer applies — The 1 GiB limit was borrowed from OpenStack Nova, which runs qemu-img in a very different environment (bare-metal hypervisors without container-level isolation). In Kubernetes, pod resource limits are the standard mechanism for constraining memory.
Describe the solution you'd like:
Remove the entire prlimit syscall mechanism:
Remove SetAddressSpaceLimit, SetCPUTimeLimit, and the prlimit syscall wrapper from pkg/system/prlimit.go
Remove AddressSpaceLimit from ProcessLimitValues
Remove maxMemory and qemuInfoLimits address space usage from pkg/image/qemu.go
Remove or simplify prlimit_test.go (the memory/CPU limit test cases)
Keep ExecWithLimits — it still provides value via context.WithTimeout for killing hung subprocesses (e.g. the 30s timeout on qemu-img info), plus stdout/stderr scanning and progress callbacks. SetCPUTimeLimit (RLIMIT_CPU) is unused in production code (only in tests) — the context timeout is the actual mechanism protecting against hangs.
Describe alternatives you've considered:
Bumping the limit to 2 GiB (architecture-dependent) — this was discussed in Prlimit Unit Test fails on s390x #3341 but is a band-aid; the fundamental incompatibility between RLIMIT_AS and Go's virtual memory model remains, and the limit value would need ongoing tuning across architectures and Go versions.
Switching to RLIMIT_RSS — not reliably enforced by the Linux kernel; cgroups are the proper mechanism for RSS limiting.
Replacing RLIMIT_AS with a transient cgroup for physical memory limiting — instead of prlimit, we could create a child cgroup per qemu-img invocation with a memory.max limit. This can be done either via systemd-run --scope -p MemoryMax=<limit> wrapping the command, or programmatically using the containerd/cgroups Go library (create a cgroup v2 manager with memory.max set, add the child PID, clean up on exit). This would correctly limit RSS/physical memory rather than virtual address space. However, it adds complexity (cgroup filesystem permissions, cleanup, cgroup v1/v2 compat) and may be overkill given that Kubernetes pod-level resource limits already constrain the importer container's total memory.
Is your feature request related to a problem? Please describe:
CDI currently uses
prlimit(RLIMIT_AS)to limit the virtual address space ofqemu-imgsubprocesses. The limit originates from an OpenStack Nova recommendation (1 GiB) and was intended to prevent malicious disk images from causingqemu-imgto allocate arbitrary amounts of memory.However,
RLIMIT_ASlimits virtual address space, not physical (RSS) memory. This is a problematic distinction that has caused real issues:Incompatibility with Go runtime — The Go runtime reserves large virtual address spaces via
mmap(for GC arenas, span management, etc.) that never translate to physical memory usage. SettingRLIMIT_ASon Go programs causes sporadic crashes. This is confirmed upstream as expected behavior, not a bug. The Go team effectively considersRLIMIT_ASincompatible with Go programs. This has caused s390x unit test failures withSIGSEGV(Prlimit Unit Test fails on s390x #3341), sporadic amd64 unit test failures withruntime: cannot allocate memory, and architecture-dependent flakiness due to varyingmmaplayouts.Redundant in a containerized environment — CDI runs in Kubernetes pods with container-level resource limits. The container runtime enforces memory limits via cgroups (which limit RSS/physical memory), providing a more robust and appropriate mechanism than
RLIMIT_AS. The address space limit adds no meaningful protection on top of cgroup constraints.Limited practical scope — The address space limit is currently only applied to
qemu-img infocalls (qemu.go:222). All otherqemu-imgoperations (convert, resize, create, rebase, commit) already passnillimits. The CPU time limit + context timeout already protect against hung processes.The original motivation no longer applies — The 1 GiB limit was borrowed from OpenStack Nova, which runs
qemu-imgin a very different environment (bare-metal hypervisors without container-level isolation). In Kubernetes, pod resource limits are the standard mechanism for constraining memory.Describe the solution you'd like:
Remove the entire
prlimitsyscall mechanism:SetAddressSpaceLimit,SetCPUTimeLimit, and theprlimitsyscall wrapper frompkg/system/prlimit.goAddressSpaceLimitfromProcessLimitValuesmaxMemoryandqemuInfoLimitsaddress space usage frompkg/image/qemu.goprlimit_test.go(the memory/CPU limit test cases)ExecWithLimits— it still provides value viacontext.WithTimeoutfor killing hung subprocesses (e.g. the 30s timeout onqemu-img info), plus stdout/stderr scanning and progress callbacks.SetCPUTimeLimit(RLIMIT_CPU) is unused in production code (only in tests) — the context timeout is the actual mechanism protecting against hangs.Describe alternatives you've considered:
RLIMIT_ASand Go's virtual memory model remains, and the limit value would need ongoing tuning across architectures and Go versions.RLIMIT_RSS— not reliably enforced by the Linux kernel; cgroups are the proper mechanism for RSS limiting.RLIMIT_ASwith a transient cgroup for physical memory limiting — instead ofprlimit, we could create a child cgroup perqemu-imginvocation with amemory.maxlimit. This can be done either viasystemd-run --scope -p MemoryMax=<limit>wrapping the command, or programmatically using thecontainerd/cgroupsGo library (create a cgroup v2 manager withmemory.maxset, add the child PID, clean up on exit). This would correctly limit RSS/physical memory rather than virtual address space. However, it adds complexity (cgroup filesystem permissions, cleanup, cgroup v1/v2 compat) and may be overkill given that Kubernetes pod-level resource limits already constrain the importer container's total memory.Additional context:
RLIMIT_ASis incompatible with Go programs