Peter Xu recently made me aware of a crash bug that turned out to be
caused by disobeying string input visitor restrictions:

    /*
     * The string input visitor does not implement support for visiting
     * QAPI structs, alternates, null, or arbitrary QTypes. Only flat lists
     * of integers (except type "size") are supported.
     */

The string input visitor has few uses outside tests/.  Let's review
them:

* object_property_parse()

  Set a QOM property to a value parsed from a string.  Uses:

  - hmp_qom_set()

    This is HMP command qom-set without -j.  Positional arguments are
    QOM path, property name and value.  Can target arbitrary QOM
    property, and therefore visit an arbitrary QAPI type.  Crashes when
    the type is one the string input visitor doesn't implement.
    Reproducer: "qom-set /machine memory junk".

    We created this bug when we added QOM properties with "funny" types
    without fully considering the implications.

  - object_apply_global_props()

    Called for each -global DRIVER.PROPERTY=VALUE and for each "compat
    prop".

    -global can target arbitrary qdev property.  Same crash risk, but I
    can't see one with a visitor-crashing type offhand.  Peter's "[PATCH
    v3 0/4] qapi/migration: Dedup migration parameter objects and fix
    tls-authz crash" adds some, e.g. "-global migration.tls-authz=junk".

    "Compat props" are purely internal.  Looks safe.

  - object_set_propv()

    Convenience interface for setting properties from C code.  Usable
    only with properties whose type the string input visitor can handle.
    I can see maybe half a dozen uses that aren't just for testing.  The
    property names are all literals.  Looks safe.

  - pc_machine_init_sgx_epc()

    Set QOM object "sgx-epc" link property "memdev" to the value of QAPI
    type SgxEPC member @memdev.  Visits a QAPI string, which is safe.

  - x86_cpu_apply_props()

    Set default CPU properties from kvm_default_props[] or
    tcg_default_props[].  Looks like these are all of boolean type,
    which is safe.

  - x86_cpu_apply_version_props()

    Set version-specific CPU properties from X86CPUDefinition member
    @versions member @props.  Looks like these are all of scalar type
    which are safe.

* hmp_migrate_set_parameter()

  This is HMP command migrate_set_parameter.  Positional arguments are
  the parameter name and value.  QAPI types are all scalar so far, which
  are safe.

Ways to fix the crash bug:

1. Lift the string input visitor restrictions

   Requires new syntax for the missing QAPI types.  I don't think
   inventing more syntax is a good idea.  We already have human-friendly
   syntax for most of the missing types: keyval_parse(), used with the
   QObject input visitor.  Comes with restrictions (see keyval.c), but
   no crashes.  We commonly use it in a way that also accepts JSON,
   unrestricted: qobject_input_visitor_new_str().

2. Fail instead of crash

   Still have to use qom-set -j for certain properties.  Fine.

   Can't use -global for certain properties.  Not so fine.  Could create
   alternative syntax that always works, like we did for qom-set.

   The two ways to do human-friendly input (string input visitor
   vs. keyval_parse() + QObject input visitor) both come with restrictions
   that may necessitate use of JSON (fine), but when exactly that's
   needed differs (not fine).

   Meh.

3. Unified solution for QAPI-based human-friendly input

   keyval_parse() + QObject input visitor works for complex QAPI types
   only.  To replace the string input visitor, we need something that
   also works for the QAPI types the string input visitor can do now:
   scalars and array of integers.

   The restriction to complex QAPI types is in keyval_parse(): it parses
   into a QDict.

   I believe we can create a variant of keyval_parse() that parses into
   a QObject instead.

   Side note: keyval_parse()'s restriction to complex QAPI types enables
   easy JSON support: qobject_input_visitor_new_str() assumes JSON when
   the string starts with '{'.  An unrestricted variant couldn't do
   that, at least not easily.  There's a reason qom-set requires a -j
   flag instead of recognizing JSON automatically.

   Affected stable external interfaces: as far as I can tell just
   -global.  QMP qom-set is not affected, since it uses the QObject
   input visitor, not the string input visitor.

   I think we should offer a JSON-based alternative t0 -global, both for
   full generality (which our human-readable syntax cannot provide), and
   because management applications are better off with JSON.

Thoughts?


Reply via email to