From: Sagi Grimberg Date: Mon, 24 Aug 2015 16:04:51 +0000 (+0300) Subject: IB/srp: Fix possible protection fault X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=7fbc67df2cd6d0b72fd5d6d3acaa79ab6f5b0224;p=openwrt%2Fstaging%2Fblogic.git IB/srp: Fix possible protection fault srp_destroy_qp is designed to indicate we are safe to continue with freeing the channel resources by modifying the qp error state, posting a dummy wr on the queue-pair and waiting for it to flush. This also holds for the channel registration pool as we are unmapping the memory region when handling a scsi response. Destroying the channel registration pool before we make sure we processed all the inflight IO might introduce a use-after-free of the registration pool. This use-after-free is demonstrated in the stack trace below where srp is trying to unmap a used FMR after the fmr_pool was already destroyed. general protection fault: 0000 [#1] SMP RIP: 0010:[] [] _raw_spin_lock_irqsave+0x1b/0x50 Call Trace: [] ib_fmr_pool_unmap+0x1a/0xb0 [ib_core] [] srp_unmap_data.isra.28+0x17d/0x250 [ib_srp] [] srp_free_req+0x2b/0x60 [ib_srp] [] srp_recv_completion+0x174/0x580 [ib_srp] [] mlx4_eq_int+0x4de/0xe50 [mlx4_core] [] mlx4_msi_x_interrupt+0x10/0x20 [mlx4_core] [] handle_irq_event_percpu+0x35/0x1b0 [] handle_irq_event+0x32/0x50 [] handle_edge_irq+0x6f/0x120 [] handle_irq+0x1a/0x30 [] do_IRQ+0x45/0xb0 [] common_interrupt+0x6d/0x6d [] cpuidle_enter_state+0x4f/0xc0 [] cpuidle_idle_call+0xcc/0x210 [] arch_cpu_idle+0xa/0x30 [] cpu_startup_entry+0xe1/0x270 [] start_secondary+0x21a/0x2c0 Reported-by: Eliott Kespi Signed-off-by: Sagi Grimberg Signed-off-by: Bart Van Assche Signed-off-by: Doug Ledford --- diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index ca98d3b47281..b481490ad257 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -554,9 +554,6 @@ static int srp_create_ch_ib(struct srp_rdma_ch *ch) "FR pool allocation failed (%d)\n", ret); goto err_qp; } - if (ch->fr_pool) - srp_destroy_fr_pool(ch->fr_pool); - ch->fr_pool = fr_pool; } else if (dev->use_fmr) { fmr_pool = srp_alloc_fmr_pool(target); if (IS_ERR(fmr_pool)) { @@ -565,9 +562,6 @@ static int srp_create_ch_ib(struct srp_rdma_ch *ch) "FMR pool allocation failed (%d)\n", ret); goto err_qp; } - if (ch->fmr_pool) - ib_destroy_fmr_pool(ch->fmr_pool); - ch->fmr_pool = fmr_pool; } if (ch->qp) @@ -581,6 +575,16 @@ static int srp_create_ch_ib(struct srp_rdma_ch *ch) ch->recv_cq = recv_cq; ch->send_cq = send_cq; + if (dev->use_fast_reg) { + if (ch->fr_pool) + srp_destroy_fr_pool(ch->fr_pool); + ch->fr_pool = fr_pool; + } else if (dev->use_fmr) { + if (ch->fmr_pool) + ib_destroy_fmr_pool(ch->fmr_pool); + ch->fmr_pool = fmr_pool; + } + kfree(init_attr); return 0;