diff options
author | Doron Tsur <doront@mellanox.com> | 2015-10-11 08:58:17 -0400 |
---|---|---|
committer | Doug Ledford <dledford@redhat.com> | 2015-10-21 15:43:12 -0400 |
commit | 0ca81a2840f77855bbad1b9f172c545c4dc9e6a4 (patch) | |
tree | 4831bbc2111ad328b50563b827936a1022d25dd4 | |
parent | ab3964ad2acfbb0dc5414d4c86fa6d8d690f27a1 (diff) |
IB/cm: Fix rb-tree duplicate free and use-after-free
ib_send_cm_sidr_rep could sometimes erase the node from the sidr
(depending on errors in the process). Since ib_send_cm_sidr_rep is
called both from cm_sidr_req_handler and cm_destroy_id, cm_id_priv
could be either erased from the rb_tree twice or not erased at all.
Fixing that by making sure it's erased only once before freeing
cm_id_priv.
Fixes: a977049dacde ('[PATCH] IB: Add the kernel CM implementation')
Signed-off-by: Doron Tsur <doront@mellanox.com>
Signed-off-by: Matan Barak <matanb@mellanox.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
-rw-r--r-- | drivers/infiniband/core/cm.c | 10 |
1 files changed, 9 insertions, 1 deletions
diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index ea4db9c1d44f..4f918b929eca 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c | |||
@@ -835,6 +835,11 @@ retest: | |||
835 | case IB_CM_SIDR_REQ_RCVD: | 835 | case IB_CM_SIDR_REQ_RCVD: |
836 | spin_unlock_irq(&cm_id_priv->lock); | 836 | spin_unlock_irq(&cm_id_priv->lock); |
837 | cm_reject_sidr_req(cm_id_priv, IB_SIDR_REJECT); | 837 | cm_reject_sidr_req(cm_id_priv, IB_SIDR_REJECT); |
838 | spin_lock_irq(&cm.lock); | ||
839 | if (!RB_EMPTY_NODE(&cm_id_priv->sidr_id_node)) | ||
840 | rb_erase(&cm_id_priv->sidr_id_node, | ||
841 | &cm.remote_sidr_table); | ||
842 | spin_unlock_irq(&cm.lock); | ||
838 | break; | 843 | break; |
839 | case IB_CM_REQ_SENT: | 844 | case IB_CM_REQ_SENT: |
840 | case IB_CM_MRA_REQ_RCVD: | 845 | case IB_CM_MRA_REQ_RCVD: |
@@ -3172,7 +3177,10 @@ int ib_send_cm_sidr_rep(struct ib_cm_id *cm_id, | |||
3172 | spin_unlock_irqrestore(&cm_id_priv->lock, flags); | 3177 | spin_unlock_irqrestore(&cm_id_priv->lock, flags); |
3173 | 3178 | ||
3174 | spin_lock_irqsave(&cm.lock, flags); | 3179 | spin_lock_irqsave(&cm.lock, flags); |
3175 | rb_erase(&cm_id_priv->sidr_id_node, &cm.remote_sidr_table); | 3180 | if (!RB_EMPTY_NODE(&cm_id_priv->sidr_id_node)) { |
3181 | rb_erase(&cm_id_priv->sidr_id_node, &cm.remote_sidr_table); | ||
3182 | RB_CLEAR_NODE(&cm_id_priv->sidr_id_node); | ||
3183 | } | ||
3176 | spin_unlock_irqrestore(&cm.lock, flags); | 3184 | spin_unlock_irqrestore(&cm.lock, flags); |
3177 | return 0; | 3185 | return 0; |
3178 | 3186 | ||