From 4848064f562bb1bb6d33fce6d9ce1f4bb3ec52d5 Mon Sep 17 00:00:00 2001 From: Justin Pettit Date: Fri, 19 Dec 2008 12:49:09 -0800 Subject: [PATCH] Fix null pointer dereference when a delete flow command is executed. A set of missing parentheses was causing an attempt to send a Flow End message even if no flow existed. The code to send the Flow End message would try to access data in the flow and cause a kernel panic. --- datapath/table-hash.c | 15 +++++++-------- datapath/table-linear.c | 10 +++++----- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/datapath/table-hash.c b/datapath/table-hash.c index a8c965e5f..2951722e9 100644 --- a/datapath/table-hash.c +++ b/datapath/table-hash.c @@ -102,8 +102,10 @@ static int table_hash_modify(struct sw_table *swt, } /* Caller must update n_flows. */ -static int do_delete(struct sw_flow **bucket, struct sw_flow *flow) +static int do_delete(struct datapath *dp, struct sw_flow **bucket, + struct sw_flow *flow, enum nx_flow_end_reason reason) { + dp_send_flow_end(dp, flow, reason); rcu_assign_pointer(*bucket, NULL); flow_deferred_free(flow); return 1; @@ -123,9 +125,8 @@ static int table_hash_delete(struct datapath *dp, struct sw_table *swt, struct sw_flow **bucket = find_bucket(swt, key); struct sw_flow *flow = *bucket; if (flow && flow_keys_equal(&flow->key, key) - && flow_has_out_port(flow, out_port)) - count = do_delete(bucket, flow); - dp_send_flow_end(dp, flow, NXFER_DELETE); + && flow_has_out_port(flow, out_port)) + count = do_delete(dp, bucket, flow, NXFER_DELETE); } else { unsigned int i; @@ -134,8 +135,7 @@ static int table_hash_delete(struct datapath *dp, struct sw_table *swt, struct sw_flow *flow = *bucket; if (flow && flow_matches_desc(&flow->key, key, strict) && flow_has_out_port(flow, out_port)) - count += do_delete(bucket, flow); - dp_send_flow_end(dp, flow, NXFER_DELETE); + count = do_delete(dp, bucket, flow, NXFER_DELETE); } } th->n_flows -= count; @@ -155,8 +155,7 @@ static int table_hash_timeout(struct datapath *dp, struct sw_table *swt) if (flow) { int reason = flow_timeout(flow); if (reason >= 0) { - count += do_delete(bucket, flow); - dp_send_flow_end(dp, flow, reason); + count += do_delete(dp, bucket, flow, reason); } } } diff --git a/datapath/table-linear.c b/datapath/table-linear.c index 3026a68be..1d5e186d2 100644 --- a/datapath/table-linear.c +++ b/datapath/table-linear.c @@ -90,8 +90,10 @@ static int table_linear_modify(struct sw_table *swt, return count; } -static int do_delete(struct sw_table *swt, struct sw_flow *flow) +static int do_delete(struct datapath *dp, struct sw_table *swt, + struct sw_flow *flow, enum nx_flow_end_reason reason) { + dp_send_flow_end(dp, flow, reason); list_del_rcu(&flow->node); list_del_rcu(&flow->iter_node); flow_deferred_free(flow); @@ -110,8 +112,7 @@ static int table_linear_delete(struct datapath *dp, struct sw_table *swt, if (flow_matches_desc(&flow->key, key, strict) && flow_has_out_port(flow, out_port) && (!strict || (flow->priority == priority))) - count += do_delete(swt, flow); - dp_send_flow_end(dp, flow, NXFER_DELETE); + count += do_delete(dp, swt, flow, NXFER_DELETE); } tl->n_flows -= count; return count; @@ -127,8 +128,7 @@ static int table_linear_timeout(struct datapath *dp, struct sw_table *swt) list_for_each_entry (flow, &tl->flows, node) { int reason = flow_timeout(flow); if (reason >= 0) { - count += do_delete(swt, flow); - dp_send_flow_end(dp, flow, reason); + count += do_delete(dp, swt, flow, reason); } } tl->n_flows -= count; -- 2.43.0