Skip to content

validate() runs before decode(), so base64 fields containing only CR/LF pass validation and decode to empty #885

Description

@u7k4rs6

Summary

GetUnikernelConfig validates the mandatory config fields while they are
still base64-encoded, then decodes them. Go's encoding/base64 skips CR
and LF, so a field containing only a newline is non-empty at validation
time and decodes to the empty string. The call returns success with all
three mandatory fields empty.

Detail

getConfigFromJSON calls validate() then decode(). validate()
checks that UnikernelType, Hypervisor and UnikernelBinary are
non-empty, but at that point they hold the encoded text.

Only CR and LF bypass this. Space and tab return illegal base64 data,
so it is specifically the two characters the decoder is documented to
skip, not whitespace in general.

Impact

Map() drops empty values, so the three mandatory annotations never
reach the persisted state. pkg/unikontainers/unikontainers.go:123 then
returns ErrNotUnikernel for that container on every subsequent Get.
New succeeds and everything after it fails, which makes this present as
a runtime bug rather than a config rejection. Around fifteen call sites in
that file read those three annotations out of state without rechecking
them.

The input is controlled by whoever builds the image.

Reproduction

urunc.json with the three mandatory fields set to a single newline:

{
  "<FILL: unikernelType tag>": "\n",
  "<FILL: hypervisor tag>": "\n",
  "<FILL: unikernelBinary tag>": "\n"
}

GetUnikernelConfig on the containing directory returns a nil error and
a config whose three mandatory fields are "".

Suggested fix

Decode before validating, so validate() inspects the values that are
actually used downstream. I have this working locally along with a
native fuzz target and a checked-in seed corpus entry for this input,
and can open a PR if that is welcome.

The annotation path in getConfigFromSpec has a related but distinct
problem (the TODO at config.go:84 means those values are never decoded
at all). I would rather raise that separately since fixing it changes
behaviour that looks deliberately parked.

Metadata

Metadata

Assignees

No one assigned

    Labels

    invalidThis doesn't seem right

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions