net/tap: fix eBPF file descriptors leakage
authorOphir Munk <ophirmu@mellanox.com>
Tue, 30 Jan 2018 16:00:28 +0000 (16:00 +0000)
committerFerruh Yigit <ferruh.yigit@intel.com>
Wed, 31 Jan 2018 19:57:29 +0000 (20:57 +0100)
When a user creates an RSS rule, the tap PMD dynamically allocates
a 'flow' data structure, and uploads BPF programs (represented by file
descriptors) to the kernel.
The kernel might reject the rule (due to filters overlap, for example)
in which case, flow memory should be freed and BPF file descriptors
should be closed.
In the corrupted code there were scenarios where BPF file descriptors
were not closed.
The fix is to add a new function - tap_flow_free(), which will make sure
to always close BPF file descriptors before freeing the flow allocated
memory.

Fixes: 036d721a8229 ("net/tap: implement RSS using eBPF")

Signed-off-by: Ophir Munk <ophirmu@mellanox.com>
Acked-by: Pascal Mazon <pascal.mazon@6wind.com>
drivers/net/tap/tap_flow.c

index 6aa53a7..533879d 100644 (file)
@@ -212,6 +212,10 @@ tap_flow_create(struct rte_eth_dev *dev,
                const struct rte_flow_action actions[],
                struct rte_flow_error *error);
 
+static void
+tap_flow_free(struct pmd_internals *pmd,
+       struct rte_flow *flow);
+
 static int
 tap_flow_destroy(struct rte_eth_dev *dev,
                 struct rte_flow *flow,
@@ -1310,6 +1314,38 @@ tap_flow_set_handle(struct rte_flow *flow)
        flow->msg.t.tcm_handle = handle;
 }
 
+/**
+ * Free the flow opened file descriptors and allocated memory
+ *
+ * @param[in] flow
+ *   Pointer to the flow to free
+ *
+ */
+static void
+tap_flow_free(struct pmd_internals *pmd, struct rte_flow *flow)
+{
+       int i;
+
+       if (!flow)
+               return;
+
+       if (pmd->rss_enabled) {
+               /* Close flow BPF file descriptors */
+               for (i = 0; i < SEC_MAX; i++)
+                       if (flow->bpf_fd[i] != 0) {
+                               close(flow->bpf_fd[i]);
+                               flow->bpf_fd[i] = 0;
+                       }
+
+               /* Release the map key for this RSS rule */
+               bpf_rss_key(KEY_CMD_RELEASE, &flow->key_idx);
+               flow->key_idx = 0;
+       }
+
+       /* Free flow allocated memory */
+       rte_free(flow);
+}
+
 /**
  * Create a flow.
  *
@@ -1428,7 +1464,7 @@ fail:
        if (remote_flow)
                rte_free(remote_flow);
        if (flow)
-               rte_free(flow);
+               tap_flow_free(pmd, flow);
        return NULL;
 }
 
@@ -1450,7 +1486,6 @@ tap_flow_destroy_pmd(struct pmd_internals *pmd,
                     struct rte_flow_error *error)
 {
        struct rte_flow *remote_flow = flow->remote_flow;
-       int i;
        int ret = 0;
 
        LIST_REMOVE(flow, next);
@@ -1476,22 +1511,6 @@ tap_flow_destroy_pmd(struct pmd_internals *pmd,
                        "couldn't receive kernel ack to our request");
                goto end;
        }
-       /* Close opened BPF file descriptors of this flow */
-       for (i = 0; i < SEC_MAX; i++)
-               if (flow->bpf_fd[i] != 0) {
-                       close(flow->bpf_fd[i]);
-                       flow->bpf_fd[i] = 0;
-               }
-
-       /* Release map key for this RSS rule */
-       ret = bpf_rss_key(KEY_CMD_RELEASE, &flow->key_idx);
-       if (ret < 0) {
-               rte_flow_error_set(
-                       error, EINVAL, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-                       "Failed to release BPF RSS key");
-
-               goto end;
-       }
 
        if (remote_flow) {
                remote_flow->msg.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
@@ -1520,7 +1539,7 @@ tap_flow_destroy_pmd(struct pmd_internals *pmd,
 end:
        if (remote_flow)
                rte_free(remote_flow);
-       rte_free(flow);
+       tap_flow_free(pmd, flow);
        return ret;
 }