Skip to content

generate: report a JSON null inside an array of objects - #176

Merged
giuseppe merged 1 commit into
containers:mainfrom
kolyshkin:fix-null-array-elements
Oct 12, 2026
Merged

giuseppe merged 1 commit into
containers:mainfrom
kolyshkin:fix-null-array-elements

Conversation

@kolyshkin

Copy link
Copy Markdown
Collaborator

make_*() returns NULL without setting *err when the value it was given is absent, and callers rely on that to tell an absent optional field from a parse failure:

ret->seccomp = make_..._seccomp (get_val (tree, "seccomp", ...), ctx, err);
if (ret->seccomp == NULL && *err != 0)
  return NULL;

A null element of an array of objects reaches make_*() as a NULL tree and therefore takes the very same path, so the failure was mistaken for an absent field and swallowed: the enclosing object was silently dropped instead of the document being rejected.

Measured against crun, one null element in the document used to give:

config before after
seccomp.syscalls[].args: [null] accepted, seccomp dropped invalid element in array 'args'
seccomp.syscalls: [null] accepted, seccomp dropped invalid element in array 'syscalls'
hooks.prestart: [null] accepted, hooks dropped invalid element in array 'prestart'
mounts: [null] rejected as (null) invalid element in array 'mounts'
linux.devices: [null] rejected as no `linux` block specified invalid element in array 'devices'
linux.namespaces: [null] rejected as no `linux` block specified invalid element in array 'namespaces'
linux.uidMappings: [null] rejected as no `linux` block specified invalid element in array 'uidMappings'

The first three are fail-open: for a runtime, a dropped seccomp block means the container ends up unconfined, and a dropped prestart hook means setup that silently never runs. The other four did fail, but pointed at the wrong place -- the linux block is present, one element inside it is not valid -- and one of them printed a NULL pointer as the error message.

Allocation failures inside make_*() had the same problem, as they too returned NULL leaving *err untouched.

This makes an absent value the only case where make_*() returns NULL without setting *err, and reports every other failure:

  • array and map element checks set an error when the callee did not
  • allocation failures report error allocating memory

tests/test-16.c covers a null element at several depths; without the change all seven cases fail.

Verified: make check 16/16 here, and crun's full python test suite rebuilt against this shows no regressions.

make_*() returns NULL without setting *err when the value it was given
is absent, and callers rely on that to tell an absent optional field
from a parse failure:

    ret->seccomp = make_..._seccomp (get_val (tree, "seccomp", ...), ctx, err);
    if (ret->seccomp == NULL && *err != 0)
      return NULL;

A null element of an array of objects reaches make_*() as a NULL tree
and therefore takes the very same path, so the failure was mistaken for
an absent field and swallowed.  The enclosing object was silently
dropped instead of the document being rejected:

    "seccomp": {"defaultAction": "SCMP_ACT_ERRNO", "syscalls": [null]}

parsed without any error at all and yielded a config with no seccomp at
all, which for a runtime means a container that ends up unconfined.
"hooks": {"prestart": [null]} likewise dropped the hooks, while
"mounts": [null] did fail, but with "(null)" as the error message.

Allocation failures inside make_*() had the same problem, as they too
returned NULL leaving *err untouched.

Make an absent value the only case where make_*() returns NULL without
setting *err, and report every other failure:

  - array and map element checks set an error when the callee did not
  - allocation failures report "error allocating memory"

Add tests/test-16.c covering a null element at several depths.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
@kolyshkin

Copy link
Copy Markdown
Collaborator Author

@giuseppe PTAL

@giuseppe
giuseppe merged commit 357330e into containers:main Oct 12, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants