api: verify message size on receipt

When a message is received, verify that it's sufficiently large to
accomodate any VLAs within message. To do that, we need a way to
calculate message size including any VLAs. This patch adds such
funcionality to vppapigen and necessary C code to use those to validate
message size on receipt. Drop messages which are malformed.

Type: improvement
Signed-off-by: Klement Sekera <ksekera@cisco.com>
Change-Id: I2903aa21dee84be6822b064795ba314de46c18f4
diff --git a/src/plugins/hs_apps/sapi/vpp_echo_bapi.c b/src/plugins/hs_apps/sapi/vpp_echo_bapi.c
index 30f3b78..2e99709 100644
--- a/src/plugins/hs_apps/sapi/vpp_echo_bapi.c
+++ b/src/plugins/hs_apps/sapi/vpp_echo_bapi.c
@@ -548,6 +548,10 @@
 #include <vnet/session/session.api.h>
 #undef vl_endianfun
 
+#define vl_calcsizefun
+#include <vnet/session/session.api.h>
+#undef vl_calcsizefun
+
 #define vl_printfun
 #include <vnet/session/session.api.h>
 #undef vl_printfun
@@ -573,7 +577,8 @@
     REPLY_MSG_ID_BASE + VL_API_##N, #n, vl_api_##n##_t_handler,               \
     vl_noop_handler, vl_api_##n##_t_endian, vl_api_##n##_t_print,             \
     sizeof (vl_api_##n##_t), 1, vl_api_##n##_t_print_json,                    \
-    vl_api_##n##_t_tojson, vl_api_##n##_t_fromjson);
+    vl_api_##n##_t_tojson, vl_api_##n##_t_fromjson,                           \
+    vl_api_##n##_t_calc_size);
   foreach_quic_echo_msg;
 #undef _
 }
diff --git a/src/plugins/tracedump/tracedump_test.c b/src/plugins/tracedump/tracedump_test.c
index 05191a4..abb8105 100644
--- a/src/plugins/tracedump/tracedump_test.c
+++ b/src/plugins/tracedump/tracedump_test.c
@@ -242,6 +242,9 @@
 #define vl_printfun
 #include <tracedump/tracedump.api.h>
 #undef vl_printfun
+#define vl_calcsizefun
+#include <tracedump/tracedump.api.h>
+#undef vl_calcsizefun
 
 void
 manual_setup_message_id_table (vat_main_t * vam)
@@ -251,7 +254,8 @@
     vl_api_trace_details_t_handler, vl_noop_handler,
     vl_api_trace_details_t_endian, vl_api_trace_details_t_print,
     sizeof (vl_api_trace_details_t), 1, vl_api_trace_details_t_print_json,
-    vl_api_trace_details_t_tojson, vl_api_trace_details_t_fromjson);
+    vl_api_trace_details_t_tojson, vl_api_trace_details_t_fromjson,
+    vl_api_trace_details_t_calc_size);
 }
 
 #define VL_API_LOCAL_SETUP_MESSAGE_ID_TABLE manual_setup_message_id_table
diff --git a/src/tools/vppapigen/vppapigen_c.py b/src/tools/vppapigen/vppapigen_c.py
index 1e18a83..f93e898 100644
--- a/src/tools/vppapigen/vppapigen_c.py
+++ b/src/tools/vppapigen/vppapigen_c.py
@@ -210,7 +210,8 @@
             if b[1] == 0:
                     continue
             write('    if (a & {})\n'.format(b[0]))
-            write('       cJSON_AddItemToArray(array, cJSON_CreateString("{}"));\n'.format(b[0]))
+            write(
+                '       cJSON_AddItemToArray(array, cJSON_CreateString("{}"));\n'.format(b[0]))
         write('    return array;\n')
         write('}\n')
 
@@ -685,7 +686,7 @@
     || defined(vl_printfun) ||defined(vl_endianfun) \\
     || defined(vl_api_version)||defined(vl_typedefs) \\
     || defined(vl_msg_name)||defined(vl_msg_name_crc_list) \\
-    || defined(vl_api_version_tuple)
+    || defined(vl_api_version_tuple) || defined(vl_calcsizefun)
 /* ok, something was selected */
 #else
 #warning no content included from {input_filename}
@@ -750,7 +751,7 @@
 
     for t in s['Define']:
         output += "\\\n_(VL_API_%s, %s, %08x) " % \
-                   (t.name.upper(), t.name, t.crc)
+            (t.name.upper(), t.name, t.crc)
     output += "\n#endif"
 
     return output
@@ -970,13 +971,13 @@
 
         write(signature.format(name=t.name, suffix='_json'))
         write('    cJSON * o = vl_api_{}_t_tojson(a);\n'.format(t.name))
-        write('    (void)s;\n');
+        write('    (void)s;\n')
         write('    char *out = cJSON_Print(o);\n')
-        write('    vl_print(handle, out);\n');
+        write('    vl_print(handle, out);\n')
         write('    cJSON_Delete(o);\n')
-        write('    cJSON_free(out);\n');
+        write('    cJSON_free(out);\n')
         write('    return handle;\n')
-        write('}\n\n');
+        write('}\n\n')
 
     write("\n#endif")
     write("\n#endif /* vl_printfun */\n")
@@ -1145,7 +1146,7 @@
 '''
 
     for t in objs:
-        if t.__class__.__name__ == 'Enum' or t.__class__.__name__ == 'EnumFlag' :
+        if t.__class__.__name__ == 'Enum' or t.__class__.__name__ == 'EnumFlag':
             output += signature.format(name=t.name)
             if t.enumtype in ENDIAN_STRINGS:
                 output += ('    *a = {}(*a);\n'
@@ -1187,6 +1188,78 @@
     return output
 
 
+def calc_size_fun(objs, modulename):
+    '''Main entry point for calculate size function generation'''
+    output = '''\
+
+/****** Calculate size functions *****/\n\
+#ifdef vl_calcsizefun
+#ifndef included_{module}_calcsizefun
+#define included_{module}_calcsizefun
+
+'''
+    output = output.format(module=modulename)
+
+    signature = '''\
+/* calculate message size of message in network byte order */
+static inline uword vl_api_{name}_t_calc_size (vl_api_{name}_t *a)
+{{
+'''
+
+    for o in objs:
+        tname = o.__class__.__name__
+
+        output += signature.format(name=o.name)
+        output += f"      return sizeof(*a)"
+        if tname == 'Using':
+            if 'length' in o.alias:
+                try:
+                    tmp = int(o.alias['length'])
+                    if tmp == 0:
+                        raise (f"Unexpected length '0' for alias {o}")
+                except:
+                    # output += f" + vl_api_{o.alias.name}_t_calc_size({o.name})"
+                    print("culprit:")
+                    print(o)
+                    print(dir(o.alias))
+                    print(o.alias)
+                    raise
+        elif tname == 'Enum' or tname == 'EnumFlag':
+            pass
+        else:
+            for b in o.block:
+                if b.type == 'Option':
+                    continue
+                elif b.type == 'Field':
+                    if b.fieldtype.startswith('vl_api_'):
+                        output += f" - sizeof(a->{b.fieldname})"
+                        output += f" + {b.fieldtype}_calc_size(&a->{b.fieldname})"
+                elif b.type == 'Array':
+                    if b.lengthfield:
+                        m = list(filter(lambda x: x.fieldname == b.lengthfield, o.block))
+                        if len(m) != 1:
+                            raise Exception(f"Expected 1 match for field '{b.lengthfield}', got '{m}'")
+                        lf = m[0]
+                        if lf.fieldtype in ENDIAN_STRINGS:
+                            output += f" + {ENDIAN_STRINGS[lf.fieldtype]}(a->{b.lengthfield}) * sizeof(a->{b.fieldname}[0])"
+                        elif lf.fieldtype == "u8":
+                            output += f" + a->{b.lengthfield} * sizeof(a->{b.fieldname}[0])"
+                        else:
+                            raise Exception(f"Don't know how to endian swap {lf.fieldtype}")
+                    else:
+                        # Fixed length strings decay to nul terminated u8
+                        if b.fieldtype == 'string':
+                            if b.modern_vla:
+                                output += f" + vl_api_string_len(&a->{b.fieldname})"
+
+        output += ";\n"
+        output += '}\n\n'
+    output += "\n#endif"
+    output += "\n#endif /* vl_calcsizefun */\n\n"
+
+    return output
+
+
 def version_tuple(s, module):
     '''Generate semantic version string'''
     output = '''\
@@ -1336,6 +1409,10 @@
 #include "{module}.api.h"
 #undef vl_endianfun
 
+#define vl_calcsizefun
+#include "{module}.api.h"
+#undef vl_calsizefun
+
 /* instantiate all the print functions we know about */
 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
 #define vl_printfun
@@ -1371,6 +1448,7 @@
               '   .print_json = vl_api_{n}_t_print_json,\n'
               '   .tojson = vl_api_{n}_t_tojson,\n'
               '   .fromjson = vl_api_{n}_t_fromjson,\n'
+              '   .calc_size = vl_api_{n}_t_calc_size,\n'
               '   .is_autoendian = {auto}}};\n'
               .format(n=s.caller, ID=s.caller.upper(),
                       auto=d.autoendian))
@@ -1389,6 +1467,7 @@
                   '  .print_json = vl_api_{n}_t_print_json,\n'
                   '  .tojson = vl_api_{n}_t_tojson,\n'
                   '  .fromjson = vl_api_{n}_t_fromjson,\n'
+                  '  .calc_size = vl_api_{n}_t_calc_size,\n'
                   '  .is_autoendian = {auto}}};\n'
                   .format(n=s.reply, ID=s.reply.upper(),
                           auto=d.autoendian))
@@ -1427,6 +1506,10 @@
 #include "{module}.api.h"
 #undef vl_endianfun
 
+#define vl_calcsizefun
+#include "{module}.api.h"
+#undef vl_calsizefun
+
 /* instantiate all the print functions we know about */
 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
 #define vl_printfun
@@ -1488,7 +1571,8 @@
               '                           sizeof(vl_api_{n}_t), 1,\n'
               '                           vl_api_{n}_t_print_json,\n'
               '                           vl_api_{n}_t_tojson,\n'
-              '                           vl_api_{n}_t_fromjson);\n'
+              '                           vl_api_{n}_t_fromjson,\n'
+              '                           vl_api_{n}_t_calc_size);\n'
               .format(n=s.reply, ID=s.reply.upper()))
         write('   hash_set_mem (vam->function_by_name, "{n}", api_{n});\n'
               .format(n=s.caller))
@@ -1510,7 +1594,8 @@
                   '                           sizeof(vl_api_{n}_t), 1,\n'
                   '                           vl_api_{n}_t_print_json,\n'
                   '                           vl_api_{n}_t_tojson,\n'
-                  '                           vl_api_{n}_t_fromjson);\n'
+                  '                           vl_api_{n}_t_fromjson,\n'
+                  '                           vl_api_{n}_t_calc_size);\n'
                   .format(n=e, ID=e.upper()))
 
     write('}\n')
@@ -1729,6 +1814,10 @@
 #include "{module}.api.h"
 #undef vl_endianfun
 
+#define vl_calcsizefun
+#include "{module}.api.h"
+#undef vl_calsizefun
+
 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
 #define vl_printfun
 #include "{module}.api.h"
@@ -1863,6 +1952,7 @@
     output += stream.getvalue()
     stream.close()
     output += endianfun(s['types'] + s['Define'], modulename)
+    output += calc_size_fun(s['types'] + s['Define'], modulename)
     output += version_tuple(s, basename)
     output += BOTTOM_BOILERPLATE.format(input_filename=basename,
                                         file_crc=s['file_crc'])
diff --git a/src/vat/api_format.c b/src/vat/api_format.c
index a759ba2..4827d55 100644
--- a/src/vat/api_format.c
+++ b/src/vat/api_format.c
@@ -64,6 +64,10 @@
 #include <vlibmemory/memclnt.api.h>
 #undef vl_endianfun
 
+#define vl_calcsizefun
+#include <vlibmemory/memclnt.api.h>
+#undef vl_calcsizefun
+
 /* instantiate all the print functions we know about */
 #if VPP_API_TEST_BUILTIN == 0
 #define vl_print(handle, ...)
@@ -2737,11 +2741,11 @@
 vat_api_hookup (vat_main_t * vam)
 {
 #define _(N, n)                                                               \
-  vl_msg_api_set_handlers (VL_API_##N + 1, #n, vl_api_##n##_t_handler_uni,    \
-			   vl_noop_handler, vl_api_##n##_t_endian,            \
-			   vl_api_##n##_t_print, sizeof (vl_api_##n##_t), 1,  \
-			   vl_api_##n##_t_print_json, vl_api_##n##_t_tojson,  \
-			   vl_api_##n##_t_fromjson);
+  vl_msg_api_set_handlers (                                                   \
+    VL_API_##N + 1, #n, vl_api_##n##_t_handler_uni, vl_noop_handler,          \
+    vl_api_##n##_t_endian, vl_api_##n##_t_print, sizeof (vl_api_##n##_t), 1,  \
+    vl_api_##n##_t_print_json, vl_api_##n##_t_tojson,                         \
+    vl_api_##n##_t_fromjson, vl_api_##n##_t_calc_size);
   foreach_vpe_api_reply_msg;
 #if VPP_API_TEST_BUILTIN == 0
   foreach_standalone_reply_msg;
diff --git a/src/vcl/vcl_bapi.c b/src/vcl/vcl_bapi.c
index 7244098..bb2b94f 100644
--- a/src/vcl/vcl_bapi.c
+++ b/src/vcl/vcl_bapi.c
@@ -276,6 +276,10 @@
 #include <vnet/session/session.api.h>
 #undef vl_endianfun
 
+#define vl_calcsizefun
+#include <vnet/session/session.api.h>
+#undef vl_calcsizefun
+
 /* instantiate all the print functions we know about */
 #define vl_printfun
 #include <vnet/session/session.api.h>
@@ -303,7 +307,8 @@
     REPLY_MSG_ID_BASE + VL_API_##N, #n, vl_api_##n##_t_handler,               \
     vl_noop_handler, vl_api_##n##_t_endian, vl_api_##n##_t_print,             \
     sizeof (vl_api_##n##_t), 1, vl_api_##n##_t_print_json,                    \
-    vl_api_##n##_t_tojson, vl_api_##n##_t_fromjson);
+    vl_api_##n##_t_tojson, vl_api_##n##_t_fromjson,                           \
+    vl_api_##n##_t_calc_size);
   foreach_sock_msg;
 #undef _
 }
diff --git a/src/vlibapi/api_common.h b/src/vlibapi/api_common.h
index 320e7c4..6b36314 100644
--- a/src/vlibapi/api_common.h
+++ b/src/vlibapi/api_common.h
@@ -132,6 +132,7 @@
   void *print_json;		/**< message print function (JSON format)  */
   void *tojson;			/**< binary to JSON convert function */
   void *fromjson;		/**< JSON to binary convert function */
+  void *calc_size;		/**< message size calculation */
   int size;			/**< message size  */
   int traced;			/**< is this message to be traced?  */
   int replay;			/**< is this message to be replayed?  */
@@ -170,17 +171,18 @@
 }
 
 /* api_shared.c prototypes */
-void vl_msg_api_handler (void *the_msg);
-void vl_msg_api_handler_no_free (void *the_msg);
-void vl_msg_api_handler_no_trace_no_free (void *the_msg);
-void vl_msg_api_trace_only (void *the_msg);
+void vl_msg_api_handler (void *the_msg, uword msg_len);
+void vl_msg_api_handler_no_free (void *the_msg, uword msg_len);
+void vl_msg_api_handler_no_trace_no_free (void *the_msg, uword msg_len);
+void vl_msg_api_trace_only (void *the_msg, uword msg_len);
 void vl_msg_api_cleanup_handler (void *the_msg);
 void vl_msg_api_replay_handler (void *the_msg);
-void vl_msg_api_socket_handler (void *the_msg);
+void vl_msg_api_socket_handler (void *the_msg, uword msg_len);
 void vl_msg_api_set_handlers (int msg_id, char *msg_name, void *handler,
 			      void *cleanup, void *endian, void *print,
 			      int msg_size, int traced, void *print_json,
-			      void *tojson, void *fromjson);
+			      void *tojson, void *fromjson,
+			      void *validate_size);
 void vl_msg_api_clean_handlers (int msg_id);
 void vl_msg_api_config (vl_msg_api_msg_config_t *);
 void vl_msg_api_set_cleanup_handler (int msg_id, void *fp);
@@ -251,6 +253,9 @@
   /** Message convert function vector */
   void *(**msg_fromjson_handlers) (cJSON *, int *);
 
+  /** Message calc size function vector */
+  uword (**msg_calc_size_funcs) (void *);
+
   /** Message name vector */
   const char **msg_names;
 
diff --git a/src/vlibapi/api_shared.c b/src/vlibapi/api_shared.c
index dd51ee5..f11344e 100644
--- a/src/vlibapi/api_shared.c
+++ b/src/vlibapi/api_shared.c
@@ -500,8 +500,8 @@
 }
 
 always_inline void
-msg_handler_internal (api_main_t * am,
-		      void *the_msg, int trace_it, int do_it, int free_it)
+msg_handler_internal (api_main_t *am, void *the_msg, uword msg_len,
+		      int trace_it, int do_it, int free_it)
 {
   u16 id = clib_net_to_host_u16 (*((u16 *) the_msg));
   u8 *(*print_fp) (void *, void *);
@@ -545,8 +545,35 @@
 	    }
 	}
 
-      if (do_it)
+      uword calc_size = 0;
+      uword (*calc_size_fp) (void *);
+      calc_size_fp = am->msg_calc_size_funcs[id];
+      ASSERT (NULL != calc_size_fp);
+      if (calc_size_fp)
 	{
+	  calc_size = (*calc_size_fp) (the_msg);
+	  ASSERT (calc_size <= msg_len);
+	  if (calc_size > msg_len)
+	    {
+	      clib_warning (
+		"Truncated message '%s' (id %u) received, calculated size "
+		"%lu is bigger than actual size %llu, message dropped.",
+		am->msg_names[id], id, calc_size, msg_len);
+	    }
+	}
+      else
+	{
+	  clib_warning ("Message '%s' (id %u) has NULL calc_size_func, cannot "
+			"verify message size is correct",
+			am->msg_names[id], id);
+	}
+
+      /* don't process message if it's truncated, otherwise byte swaps
+       * and stuff could corrupt memory even beyond message if it's malicious
+       * e.g. VLA length field set to 1M elements, but VLA empty */
+      if (do_it && calc_size <= msg_len)
+	{
+
 	  if (!am->is_mp_safe[id])
 	    {
 	      vl_msg_api_barrier_trace_context (am->msg_names[id]);
@@ -569,6 +596,7 @@
 	  if (PREDICT_FALSE (vec_len (am->perf_counter_cbs) != 0))
 	    clib_call_callbacks (am->perf_counter_cbs, am, id,
 				 1 /* after */ );
+
 	  if (!am->is_mp_safe[id])
 	    vl_msg_api_barrier_release ();
 	}
@@ -767,32 +795,30 @@
 }
 
 void
-vl_msg_api_handler (void *the_msg)
+vl_msg_api_handler (void *the_msg, uword msg_len)
 {
   api_main_t *am = vlibapi_get_main ();
 
-  msg_handler_internal (am, the_msg,
-			(am->rx_trace
-			 && am->rx_trace->enabled) /* trace_it */ ,
-			1 /* do_it */ , 1 /* free_it */ );
+  msg_handler_internal (am, the_msg, msg_len,
+			(am->rx_trace && am->rx_trace->enabled) /* trace_it */,
+			1 /* do_it */, 1 /* free_it */);
 }
 
 void
-vl_msg_api_handler_no_free (void *the_msg)
+vl_msg_api_handler_no_free (void *the_msg, uword msg_len)
 {
   api_main_t *am = vlibapi_get_main ();
-  msg_handler_internal (am, the_msg,
-			(am->rx_trace
-			 && am->rx_trace->enabled) /* trace_it */ ,
-			1 /* do_it */ , 0 /* free_it */ );
+  msg_handler_internal (am, the_msg, msg_len,
+			(am->rx_trace && am->rx_trace->enabled) /* trace_it */,
+			1 /* do_it */, 0 /* free_it */);
 }
 
 void
-vl_msg_api_handler_no_trace_no_free (void *the_msg)
+vl_msg_api_handler_no_trace_no_free (void *the_msg, uword msg_len)
 {
   api_main_t *am = vlibapi_get_main ();
-  msg_handler_internal (am, the_msg, 0 /* trace_it */ , 1 /* do_it */ ,
-			0 /* free_it */ );
+  msg_handler_internal (am, the_msg, msg_len, 0 /* trace_it */, 1 /* do_it */,
+			0 /* free_it */);
 }
 
 /*
@@ -805,14 +831,13 @@
  *
  */
 void
-vl_msg_api_trace_only (void *the_msg)
+vl_msg_api_trace_only (void *the_msg, uword msg_len)
 {
   api_main_t *am = vlibapi_get_main ();
 
-  msg_handler_internal (am, the_msg,
-			(am->rx_trace
-			 && am->rx_trace->enabled) /* trace_it */ ,
-			0 /* do_it */ , 0 /* free_it */ );
+  msg_handler_internal (am, the_msg, msg_len,
+			(am->rx_trace && am->rx_trace->enabled) /* trace_it */,
+			0 /* do_it */, 0 /* free_it */);
 }
 
 void
@@ -863,14 +888,13 @@
  * vl_msg_api_socket_handler
  */
 void
-vl_msg_api_socket_handler (void *the_msg)
+vl_msg_api_socket_handler (void *the_msg, uword msg_len)
 {
   api_main_t *am = vlibapi_get_main ();
 
-  msg_handler_internal (am, the_msg,
-			(am->rx_trace
-			 && am->rx_trace->enabled) /* trace_it */ ,
-			1 /* do_it */ , 0 /* free_it */ );
+  msg_handler_internal (am, the_msg, msg_len,
+			(am->rx_trace && am->rx_trace->enabled) /* trace_it */,
+			1 /* do_it */, 0 /* free_it */);
 }
 
 #define foreach_msg_api_vector                                                \
@@ -882,6 +906,7 @@
   _ (msg_print_json_handlers)                                                 \
   _ (msg_tojson_handlers)                                                     \
   _ (msg_fromjson_handlers)                                                   \
+  _ (msg_calc_size_funcs)                                                     \
   _ (api_trace_cfg)                                                           \
   _ (message_bounce)                                                          \
   _ (is_mp_safe)                                                              \
@@ -927,6 +952,7 @@
   am->msg_print_json_handlers[c->id] = c->print_json;
   am->msg_tojson_handlers[c->id] = c->tojson;
   am->msg_fromjson_handlers[c->id] = c->fromjson;
+  am->msg_calc_size_funcs[c->id] = c->calc_size;
   am->message_bounce[c->id] = c->message_bounce;
   am->is_mp_safe[c->id] = c->is_mp_safe;
   am->is_autoendian[c->id] = c->is_autoendian;
@@ -948,7 +974,8 @@
 void
 vl_msg_api_set_handlers (int id, char *name, void *handler, void *cleanup,
 			 void *endian, void *print, int size, int traced,
-			 void *print_json, void *tojson, void *fromjson)
+			 void *print_json, void *tojson, void *fromjson,
+			 void *calc_size)
 {
   vl_msg_api_msg_config_t cfg;
   vl_msg_api_msg_config_t *c = &cfg;
@@ -969,6 +996,7 @@
   c->tojson = tojson;
   c->fromjson = fromjson;
   c->print_json = print_json;
+  c->calc_size = calc_size;
   vl_msg_api_config (c);
 }
 
@@ -999,8 +1027,11 @@
 {
   uword msg;
 
-  while (!svm_queue_sub (q, (u8 *) & msg, SVM_Q_WAIT, 0))
-    vl_msg_api_handler ((void *) msg);
+  while (!svm_queue_sub (q, (u8 *) &msg, SVM_Q_WAIT, 0))
+    {
+      msgbuf_t *msgbuf = (msgbuf_t *) ((u8 *) msg - offsetof (msgbuf_t, data));
+      vl_msg_api_handler ((void *) msg, ntohl (msgbuf->data_len));
+    }
 }
 
 u32
diff --git a/src/vlibmemory/memclnt_api.c b/src/vlibmemory/memclnt_api.c
index 2b4a239..87bb36a 100644
--- a/src/vlibmemory/memclnt_api.c
+++ b/src/vlibmemory/memclnt_api.c
@@ -58,6 +58,10 @@
 #include <vlibmemory/vl_memory_api_h.h>
 #undef vl_endianfun
 
+#define vl_calcsizefun
+#include <vlibmemory/vl_memory_api_h.h>
+#undef vl_calcsizefun
+
 static void
 vl_api_get_first_msg_id_t_handler (vl_api_get_first_msg_id_t *mp)
 {
@@ -177,6 +181,7 @@
       c->print_json = vl_api_##n##_t_print_json;                              \
       c->tojson = vl_api_##n##_t_tojson;                                      \
       c->fromjson = vl_api_##n##_t_fromjson;                                  \
+      c->calc_size = vl_api_##n##_t_calc_size;                                \
       c->size = sizeof (vl_api_##n##_t);                                      \
       c->traced = 1;	     /* trace, so these msgs print */                 \
       c->replay = 0;	     /* don't replay client create/delete msgs */     \
@@ -505,8 +510,9 @@
 	      vec_add (long_msg, msg, msg_len);
 	    }
 	  msg = long_msg;
+	  msg_len = vec_len (long_msg);
 	}
-      vl_msg_api_handler_no_trace_no_free (msg);
+      vl_msg_api_handler_no_trace_no_free (msg, msg_len);
     }
 
   /* Free what we've been given. */
@@ -704,20 +710,20 @@
 {
   api_main_t *am = vlibapi_get_main ();
 #define _(N, n)                                                               \
-  vl_msg_api_set_handlers (VL_API_##N, #n, vl_api_##n##_t_handler,            \
-			   vl_noop_handler, vl_noop_handler,                  \
-			   vl_api_##n##_t_print, sizeof (vl_api_##n##_t),     \
-			   0 /* do not trace */, vl_api_##n##_t_print_json,   \
-			   vl_api_##n##_t_tojson, vl_api_##n##_t_fromjson);
+  vl_msg_api_set_handlers (                                                   \
+    VL_API_##N, #n, vl_api_##n##_t_handler, vl_noop_handler, vl_noop_handler, \
+    vl_api_##n##_t_print, sizeof (vl_api_##n##_t), 0 /* do not trace */,      \
+    vl_api_##n##_t_print_json, vl_api_##n##_t_tojson,                         \
+    vl_api_##n##_t_fromjson, vl_api_##n##_t_calc_size);
   foreach_rpc_api_msg;
 #undef _
 
 #define _(N, n)                                                               \
-  vl_msg_api_set_handlers (VL_API_##N, #n, vl_api_##n##_t_handler,            \
-			   vl_noop_handler, vl_noop_handler,                  \
-			   vl_api_##n##_t_print, sizeof (vl_api_##n##_t),     \
-			   1 /* do trace */, vl_api_##n##_t_print_json,       \
-			   vl_api_##n##_t_tojson, vl_api_##n##_t_fromjson);
+  vl_msg_api_set_handlers (                                                   \
+    VL_API_##N, #n, vl_api_##n##_t_handler, vl_noop_handler, vl_noop_handler, \
+    vl_api_##n##_t_print, sizeof (vl_api_##n##_t), 1 /* do trace */,          \
+    vl_api_##n##_t_print_json, vl_api_##n##_t_tojson,                         \
+    vl_api_##n##_t_fromjson, vl_api_##n##_t_calc_size);
   foreach_plugin_trace_msg;
 #undef _
 
diff --git a/src/vlibmemory/memory_client.c b/src/vlibmemory/memory_client.c
index f0b05b7..54bc8d8 100644
--- a/src/vlibmemory/memory_client.c
+++ b/src/vlibmemory/memory_client.c
@@ -39,6 +39,10 @@
 #include <vlibmemory/vl_memory_api_h.h>
 #undef vl_endianfun
 
+#define vl_calcsizefun
+#include <vlibmemory/vl_memory_api_h.h>
+#undef vl_calcsizefun
+
 /* instantiate all the print functions we know about */
 #define vl_print(handle, ...) clib_warning (__VA_ARGS__)
 #define vl_printfun
@@ -240,7 +244,8 @@
 	}
       rv = clib_net_to_host_u32 (rp->response);
 
-      vl_msg_api_handler ((void *) rp);
+      msgbuf_t *msgbuf = (msgbuf_t *) ((u8 *) rp - offsetof (msgbuf_t, data));
+      vl_msg_api_handler ((void *) rp, ntohl (msgbuf->data_len));
       break;
     }
   return (rv);
@@ -289,6 +294,7 @@
   svm_queue_t *vl_input_queue;
   api_main_t *am = vlibapi_get_main ();
   time_t begin;
+  msgbuf_t *msgbuf;
 
   vl_input_queue = am->vl_input_queue;
   vl_client_send_disconnect (0 /* wait for reply */ );
@@ -321,10 +327,12 @@
       if (ntohs (rp->_vl_msg_id) != VL_API_MEMCLNT_DELETE_REPLY)
 	{
 	  clib_warning ("queue drain: %d", ntohs (rp->_vl_msg_id));
-	  vl_msg_api_handler ((void *) rp);
+	  msgbuf = (msgbuf_t *) ((u8 *) rp - offsetof (msgbuf_t, data));
+	  vl_msg_api_handler ((void *) rp, ntohl (msgbuf->data_len));
 	  continue;
 	}
-      vl_msg_api_handler ((void *) rp);
+      msgbuf = (msgbuf_t *) ((u8 *) rp - offsetof (msgbuf_t, data));
+      vl_msg_api_handler ((void *) rp, ntohl (msgbuf->data_len));
       break;
     }
 
@@ -364,11 +372,11 @@
 {
   api_main_t *am = vlibapi_get_main ();
 #define _(N, n)                                                               \
-  vl_msg_api_set_handlers (VL_API_##N, #n, vl_api_##n##_t_handler,            \
-			   noop_handler, vl_api_##n##_t_endian,               \
-			   vl_api_##n##_t_print, sizeof (vl_api_##n##_t), 0,  \
-			   vl_api_##n##_t_print_json, vl_api_##n##_t_tojson,  \
-			   vl_api_##n##_t_fromjson);                          \
+  vl_msg_api_set_handlers (                                                   \
+    VL_API_##N, #n, vl_api_##n##_t_handler, noop_handler,                     \
+    vl_api_##n##_t_endian, vl_api_##n##_t_print, sizeof (vl_api_##n##_t), 0,  \
+    vl_api_##n##_t_print_json, vl_api_##n##_t_tojson,                         \
+    vl_api_##n##_t_fromjson, vl_api_##n##_t_calc_size);                       \
   am->api_trace_cfg[VL_API_##N].replay_enable = 0;
   foreach_api_msg;
 #undef _
@@ -569,6 +577,11 @@
   old_handler = am->msg_handlers[VL_API_GET_FIRST_MSG_ID_REPLY];
   am->msg_handlers[VL_API_GET_FIRST_MSG_ID_REPLY] = (void *)
     vl_api_get_first_msg_id_reply_t_handler;
+  if (!am->msg_calc_size_funcs[VL_API_GET_FIRST_MSG_ID_REPLY])
+    {
+      am->msg_calc_size_funcs[VL_API_GET_FIRST_MSG_ID_REPLY] =
+	(uword (*) (void *)) vl_api_get_first_msg_id_reply_t_calc_size;
+    }
 
   /* Ask the data-plane for the message-ID base of the indicated plugin */
   mm->first_msg_id_reply_ready = 0;
diff --git a/src/vlibmemory/socket_api.c b/src/vlibmemory/socket_api.c
index ce834a7..3e3f7d5 100644
--- a/src/vlibmemory/socket_api.c
+++ b/src/vlibmemory/socket_api.c
@@ -45,6 +45,10 @@
 #include <vlibmemory/vl_memory_api_h.h>
 #undef vl_endianfun
 
+#define vl_calcsizefun
+#include <vlibmemory/vl_memory_api_h.h>
+#undef vl_calcsizefun
+
 socket_main_t socket_main;
 
 #define SOCK_API_REG_HANDLE_BIT (1<<31)
@@ -200,7 +204,7 @@
 
   u8 *the_msg = (u8 *) (mbp->data);
   socket_main.current_rp = rp;
-  vl_msg_api_socket_handler (the_msg);
+  vl_msg_api_socket_handler (the_msg, ntohl (mbp->data_len));
   socket_main.current_rp = 0;
 }
 
@@ -792,11 +796,11 @@
     return 0;
 
 #define _(N, n, t)                                                            \
-  vl_msg_api_set_handlers (VL_API_##N, #n, vl_api_##n##_t_handler,            \
-			   vl_noop_handler, vl_api_##n##_t_endian,            \
-			   vl_api_##n##_t_print, sizeof (vl_api_##n##_t), t,  \
-			   vl_api_##n##_t_print_json, vl_api_##n##_t_tojson,  \
-			   vl_api_##n##_t_fromjson);                          \
+  vl_msg_api_set_handlers (                                                   \
+    VL_API_##N, #n, vl_api_##n##_t_handler, vl_noop_handler,                  \
+    vl_api_##n##_t_endian, vl_api_##n##_t_print, sizeof (vl_api_##n##_t), t,  \
+    vl_api_##n##_t_print_json, vl_api_##n##_t_tojson,                         \
+    vl_api_##n##_t_fromjson, vl_api_##n##_t_calc_size);                       \
   am->api_trace_cfg[VL_API_##N].replay_enable = 0;
   foreach_vlib_api_msg;
 #undef _
diff --git a/src/vlibmemory/socket_client.c b/src/vlibmemory/socket_client.c
index 2fb6b8a..7082d8b 100644
--- a/src/vlibmemory/socket_client.c
+++ b/src/vlibmemory/socket_client.c
@@ -36,6 +36,10 @@
 #include <vlibmemory/vl_memory_api_h.h>
 #undef vl_endianfun
 
+#define vl_calcsizefun
+#include <vlibmemory/vl_memory_api_h.h>
+#undef vl_calcsizefun
+
 /* instantiate all the print functions we know about */
 #define vl_print(handle, ...) clib_warning (__VA_ARGS__)
 #define vl_printfun
@@ -134,7 +138,7 @@
 
       if (vec_len (scm->socket_rx_buffer) >= data_len + sizeof (*mbp))
 	{
-	  vl_msg_api_socket_handler ((void *) (mbp->data));
+	  vl_msg_api_socket_handler ((void *) (mbp->data), data_len);
 
 	  if (vec_len (scm->socket_rx_buffer) == data_len + sizeof (*mbp))
 	    _vec_len (scm->socket_rx_buffer) = 0;
@@ -433,11 +437,11 @@
 {
 
 #define _(N, n)                                                               \
-  vl_msg_api_set_handlers (VL_API_##N, #n, vl_api_##n##_t_handler,            \
-			   noop_handler, vl_api_##n##_t_endian,               \
-			   vl_api_##n##_t_print, sizeof (vl_api_##n##_t), 0,  \
-			   vl_api_##n##_t_print_json, vl_api_##n##_t_tojson,  \
-			   vl_api_##n##_t_fromjson);
+  vl_msg_api_set_handlers (                                                   \
+    VL_API_##N, #n, vl_api_##n##_t_handler, noop_handler,                     \
+    vl_api_##n##_t_endian, vl_api_##n##_t_print, sizeof (vl_api_##n##_t), 0,  \
+    vl_api_##n##_t_print_json, vl_api_##n##_t_tojson,                         \
+    vl_api_##n##_t_fromjson, vl_api_##n##_t_calc_size);
   foreach_sock_client_api_msg;
 #undef _
 }
diff --git a/src/vnet/ip/ip_api.c b/src/vnet/ip/ip_api.c
index e197057..b1b7ff3 100644
--- a/src/vnet/ip/ip_api.c
+++ b/src/vnet/ip/ip_api.c
@@ -514,7 +514,9 @@
     goto out;
 
   if (0 != n_paths)
-    vec_validate (rpaths, n_paths - 1);
+    {
+      vec_validate (rpaths, n_paths - 1);
+    }
 
   for (ii = 0; ii < n_paths; ii++)
     {
diff --git a/src/vnet/ip/ip_test.c b/src/vnet/ip/ip_test.c
index c47cd3d..f87b47f 100644
--- a/src/vnet/ip/ip_test.c
+++ b/src/vnet/ip/ip_test.c
@@ -36,6 +36,10 @@
 #include <vnet/ip/ip.api.h>
 #undef vl_endianfun
 
+#define vl_calcsizefun
+#include <vnet/ip/ip.api.h>
+#undef vl_calcsizefun
+
 typedef struct
 {
   /* API message ID base */
diff --git a/src/vnet/ipsec/ipsec_test.c b/src/vnet/ipsec/ipsec_test.c
index f399032..f3a9992 100644
--- a/src/vnet/ipsec/ipsec_test.c
+++ b/src/vnet/ipsec/ipsec_test.c
@@ -26,6 +26,10 @@
 #include <vnet/ipsec/ipsec.api.h>
 #undef vl_endianfun
 
+#define vl_calcsizefun
+#include <vnet/ipsec/ipsec.api.h>
+#undef vl_calcsizefun
+
 typedef struct
 {
   /* API message ID base */
diff --git a/src/vnet/l2/l2_test.c b/src/vnet/l2/l2_test.c
index c7cd1d2..3be4a46 100644
--- a/src/vnet/l2/l2_test.c
+++ b/src/vnet/l2/l2_test.c
@@ -28,6 +28,10 @@
 #include <vnet/l2/l2.api.h>
 #undef vl_endianfun
 
+#define vl_calcsizefun
+#include <vnet/l2/l2.api.h>
+#undef vl_calcsizefun
+
 typedef struct
 {
   /* API message ID base */
diff --git a/src/vnet/srmpls/sr_mpls_api.c b/src/vnet/srmpls/sr_mpls_api.c
index 7d42f1b..45107f0 100644
--- a/src/vnet/srmpls/sr_mpls_api.c
+++ b/src/vnet/srmpls/sr_mpls_api.c
@@ -39,6 +39,10 @@
 #include <vnet/srmpls/sr_mpls.api.h>
 #undef vl_endianfun
 
+#define vl_calcsizefun
+#include <vnet/srmpls/sr_mpls.api.h>
+#undef vl_calcsizefun
+
 #define vl_printfun
 #include <vnet/srmpls/sr_mpls.api.h>
 #undef vl_printfun
@@ -194,7 +198,8 @@
     REPLY_MSG_ID_BASE + VL_API_##N, #n, vl_api_##n##_t_handler,               \
     vl_noop_handler, vl_api_##n##_t_endian, vl_api_##n##_t_print,             \
     sizeof (vl_api_##n##_t), 1, vl_api_##n##_t_print_json,                    \
-    vl_api_##n##_t_tojson, vl_api_##n##_t_fromjson);
+    vl_api_##n##_t_tojson, vl_api_##n##_t_fromjson,                           \
+    vl_api_##n##_t_calc_size);
   foreach_vpe_api_msg;
 #undef _
 
@@ -207,7 +212,8 @@
     vl_api_sr_mpls_policy_add_t_handler, vl_noop_handler,
     vl_api_sr_mpls_policy_add_t_endian, vl_api_sr_mpls_policy_add_t_print, 256,
     1, vl_api_sr_mpls_policy_add_t_print_json,
-    vl_api_sr_mpls_policy_mod_t_tojson, vl_api_sr_mpls_policy_mod_t_fromjson);
+    vl_api_sr_mpls_policy_add_t_tojson, vl_api_sr_mpls_policy_add_t_fromjson,
+    vl_api_sr_mpls_policy_add_t_calc_size);
 
   /*
    * Manually register the sr policy mod msg, so we trace enough bytes
@@ -218,7 +224,8 @@
     vl_api_sr_mpls_policy_mod_t_handler, vl_noop_handler,
     vl_api_sr_mpls_policy_mod_t_endian, vl_api_sr_mpls_policy_mod_t_print, 256,
     1, vl_api_sr_mpls_policy_mod_t_print_json,
-    vl_api_sr_mpls_policy_mod_t_tojson, vl_api_sr_mpls_policy_mod_t_fromjson);
+    vl_api_sr_mpls_policy_mod_t_tojson, vl_api_sr_mpls_policy_mod_t_fromjson,
+    vl_api_sr_mpls_policy_mod_t_calc_size);
 
   /*
    * Set up the (msg_name, crc, message-id) table