static int make_openflow_device(unsigned int minor, char **fnp);
static char *odp_actions_to_string(const union odp_action actions[],
size_t n_actions);
+static void check_rw_odp_flow(struct odp_flow *);
int
dpif_open(const char *name, struct dpif *dpif)
int
dpif_flow_del(struct dpif *dpif, struct odp_flow *flow)
{
+ check_rw_odp_flow(flow);
return IOCTL(dpif, ODP_FLOW_DEL, flow);
}
int
dpif_flow_query(const struct dpif *dpif, struct odp_flow *flow)
{
+ check_rw_odp_flow(flow);
return IOCTL(dpif, ODP_FLOW_QUERY, flow);
}
struct odp_flow flows[], size_t n)
{
struct odp_flowvec fv;
+ size_t i;
+
fv.flows = flows;
fv.n_flows = n;
+ for (i = 0; i < n; i++) {
+ check_rw_odp_flow(&flows[i]);
+ }
return IOCTL(dpif, ODP_FLOW_QUERY_MULTIPLE, &fv);
}
}
return ds_cstr(&ds);
}
+
+/* There is a tendency to construct odp_flow objects on the stack and to
+ * forget to properly initialize their "actions" and "n_actions" members.
+ * When this happens, we get memory corruption because the kernel
+ * writes through the random pointer that is in the "actions" member.
+ *
+ * This function attempts to combat the problem by:
+ *
+ * - Forcing a segfault if "actions" points to an invalid region (instead
+ * of just getting back EFAULT, which can be easily missed in the log).
+ *
+ * - Storing a distinctive value that is likely to cause an
+ * easy-to-identify error later if it is dereferenced, etc.
+ *
+ * - Triggering a warning on uninitialized memory from Valgrind if
+ * "actions" or "n_actions" was not initialized.
+ */
+static void
+check_rw_odp_flow(struct odp_flow *flow)
+{
+ if (flow->n_actions) {
+ memset(&flow->actions[0], 0xcc, sizeof flow->actions[0]);
+ }
+}