Code

curl_json plugin: Skip unexpected non-map values.
authorFlorian Forster <octo@collectd.org>
Tue, 13 Sep 2016 08:44:46 +0000 (10:44 +0200)
committerFlorian Forster <octo@collectd.org>
Tue, 13 Sep 2016 08:45:01 +0000 (10:45 +0200)
Assume, for example, the config `Key "*/foo"`. This config expects JSON
in the form:

    {
      "bar": {
        "foo": 1337
      }
    }

If the available JSON is instead:

    {
      "error_code": 0,
      "bar": {
        "foo": 1337
      }
    }

the code will take a look at the zero associated with "error_code" and
determine that a map (with key "foo") is expected instead. Previously
the code would continue, eventually calling `cj_get_type()` which
expects that `key->type` is a valid pointer, resulting in a segmentation
fault.

This patch does three things to ensure that this segmentation fault does
not happen again:

1.  `cj_get_type()` checks its argument to make sure it is valid before
    dereferencing any pointers.
2.  In case a non-map is found when a map is expected, the code will
    return instead of limping on.
3.  After calling `cj_cb_inc_array_index()`, which may update the key,
    make sure that it actually did and that key is valid now.

Fixes: #1896
src/curl_json.c

index 4188f37862bf7f639e9bfa01fddf419245b28b31..a547ddcd42a53ac9198475cb78387aed95f87c7b 100644 (file)
@@ -143,6 +143,9 @@ static int cj_get_type (cj_key_t *key)
 {
   const data_set_t *ds;
 
+  if ((key == NULL) || !CJ_IS_KEY (key))
+    return -EINVAL;
+
   ds = plugin_get_ds (key->type);
   if (ds == NULL)
   {
@@ -226,12 +229,15 @@ static int cj_cb_number (void *ctx,
   buffer[sizeof (buffer) - 1] = 0;
 
   if ((key == NULL) || !CJ_IS_KEY (key)) {
-    if (key != NULL && !db->state[db->depth].in_array/*can be inhomogeneous*/)
+    if (key != NULL && !db->state[db->depth].in_array/*can be inhomogeneous*/) {
       NOTICE ("curl_json plugin: Found \"%s\", but the configuration expects"
               " a map.", buffer);
+      return (CJ_CB_CONTINUE);
+    }
+
     cj_cb_inc_array_index (ctx, /* update_key = */ 1);
     key = db->state[db->depth].key;
-    if (key == NULL) {
+    if ((key == NULL) || !CJ_IS_KEY (key)) {
       return (CJ_CB_CONTINUE);
     }
   }