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
# parseCmdLine() wraps multi-word Linux-unikernel args in unescaped single quotes, corrupting urunit's boot-cmdline argument parsing when an arg itself contains a quote #897
What happened:
When urunc runs a Linux-based unikernel guest (the linux unikernel type, driven by the urunit init process), it builds the guest's init= boot-parameter string by joining Process.Args from the OCI spec. To let urunit recover which whitespace-separated tokens belong to one original argument, parseCmdLine() wraps any argument containing a space in single quotes, via plain string concatenation, with no escaping of quote characters already present in the argument.
l.App/l.Command are then concatenated unescaped into the guest kernel boot parameters in CommandString() at pkg/unikontainers/unikernels/linux.go:124-126:
If an argument contains both a space and a single quote, for example sh -c "echo it's fine", the naive "'" + arg + "'" wrap produces 'echo it's fine', an unbalanced 3-quote sequence instead of 2. This corrupts the quote-delimited token stream urunit parses out of /proc/cmdline to reconstruct argv for the guest's init process.
What you expected to happen:
Arguments containing a single quote should be safely escaped when embedded in the boot cmdline (or rejected with a clear error), so the guest's init process always receives exactly the arguments the user specified.
How to reproduce:
Build a Linux-unikernel-type urunc container (bima image using urunit as init) with an OCI spec process.args entry containing a space and a single quote, e.g. ["/urunit", "sh", "-c", "echo it's broken"].
Run the container with urunc create/urunc run.
Inspect the guest's /proc/cmdline (or the argv urunit actually launches): the init=... -- ... segment contains 'sh' 'echo it's broken', an unbalanced quote sequence, instead of the two intended tokens.
Observe urunit either fails to parse the cmdline correctly or launches init with a different, wrong argument split than what was configured.
Impact:
Silent corruption of the command actually executed inside Linux-based unikernel guests whenever a workload's argument legitimately contains a single quote alongside whitespace (a common shell pattern, e.g. sh -c "it's ..."). Because the corrupted string is image-author-controlled and unescaped in a token-boundary-sensitive parser, the damage isn't confined to that one argument's text, it shifts where the parser believes subsequent arguments start and end, so containers can run the wrong command with no error surfaced to the user.
Suggested fix:
Escape embedded single quotes when wrapping an argument (shell-style ' to '\''), or reject arguments containing quote characters with a clear error until proper escaping is implemented.
Environment:
urunc version: main branch
Hypervisor backend: any hypervisor used with the linux unikernel type (QEMU, Firecracker, Cloud Hypervisor), the bug is in the shared guest driver, not hypervisor-specific code
OS: Linux
PROOF IT IS REAL:
Verified current code directly: pkg/unikontainers/unikernels/linux.go lines 248-272 (parseCmdLine) and 124-126 (CommandString) match exactly as quoted above, no escaping of quote characters exists anywhere in the file, only strings.TrimSpace.
This is distinct from the closed issue QEMU Command Injection via OCI Annotation causing args.Command Split on Spaces #666 ("QEMU Command Injection via OCI Annotation causing args.Command Split on Spaces"), which concerned pkg/unikontainers/hypervisors/qemu.go's BuildExecCmd splitting cmdString by spaces, confirmed that code now appends args.Command as a single unsplit argument to -append, so that issue is already fixed and unrelated to this one, which is about how args.Command's content gets built in the first place.
Not one of the 5 pre-existing local fix branches (tap fd leak, mountinfo unescape, pivot_root decision, block-volume rollback, exec-stub Argo hang), none touch pkg/unikontainers/unikernels/.
Duplicate searches against open/closed issues and open/merged PRs for parseCmdLine, normalizedArgs, wrap multi-word, quoting, single quote, escape argument, urunit returned no matching prior report (only unrelated urunit topics like rlimits, graceful shutdown, and QEMU Command Injection via OCI Annotation causing args.Command Split on Spaces #666 above).
What happened:
When urunc runs a Linux-based unikernel guest (the
linuxunikernel type, driven by theurunitinit process), it builds the guest'sinit=boot-parameter string by joiningProcess.Argsfrom the OCI spec. To leturunitrecover which whitespace-separated tokens belong to one original argument,parseCmdLine()wraps any argument containing a space in single quotes, via plain string concatenation, with no escaping of quote characters already present in the argument.Root cause:
pkg/unikontainers/unikernels/linux.go:248-272:l.App/l.Commandare then concatenated unescaped into the guest kernel boot parameters inCommandString()atpkg/unikontainers/unikernels/linux.go:124-126:If an argument contains both a space and a single quote, for example
sh -c "echo it's fine", the naive"'" + arg + "'"wrap produces'echo it's fine', an unbalanced 3-quote sequence instead of 2. This corrupts the quote-delimited token streamurunitparses out of/proc/cmdlineto reconstruct argv for the guest's init process.What you expected to happen:
Arguments containing a single quote should be safely escaped when embedded in the boot cmdline (or rejected with a clear error), so the guest's init process always receives exactly the arguments the user specified.
How to reproduce:
urunitas init) with an OCI specprocess.argsentry containing a space and a single quote, e.g.["/urunit", "sh", "-c", "echo it's broken"].urunc create/urunc run./proc/cmdline(or the argv urunit actually launches): theinit=... -- ...segment contains'sh' 'echo it's broken', an unbalanced quote sequence, instead of the two intended tokens.Impact:
Silent corruption of the command actually executed inside Linux-based unikernel guests whenever a workload's argument legitimately contains a single quote alongside whitespace (a common shell pattern, e.g.
sh -c "it's ..."). Because the corrupted string is image-author-controlled and unescaped in a token-boundary-sensitive parser, the damage isn't confined to that one argument's text, it shifts where the parser believes subsequent arguments start and end, so containers can run the wrong command with no error surfaced to the user.Suggested fix:
Escape embedded single quotes when wrapping an argument (shell-style
'to'\''), or reject arguments containing quote characters with a clear error until proper escaping is implemented.Environment:
linuxunikernel type (QEMU, Firecracker, Cloud Hypervisor), the bug is in the shared guest driver, not hypervisor-specific codePROOF IT IS REAL:
pkg/unikontainers/unikernels/linux.golines 248-272 (parseCmdLine) and 124-126 (CommandString) match exactly as quoted above, no escaping of quote characters exists anywhere in the file, onlystrings.TrimSpace.pkg/unikontainers/hypervisors/qemu.go'sBuildExecCmdsplittingcmdStringby spaces, confirmed that code now appendsargs.Commandas a single unsplit argument to-append, so that issue is already fixed and unrelated to this one, which is about howargs.Command's content gets built in the first place.pkg/unikontainers/unikernels/.parseCmdLine,normalizedArgs,wrap multi-word,quoting,single quote,escape argument,urunitreturned no matching prior report (only unrelated urunit topics like rlimits, graceful shutdown, and QEMU Command Injection via OCI Annotation causing args.Command Split on Spaces #666 above).