Target drivers like ib_srpt can call transport_deregister_session() while core_tpg_del_initiator_node_acl() is processing sess_acl_list. Avoid that this scenario triggers a use-after-free by postponing freeing a session object until core_tpg_del_initiator_node_acl() has finished accessing that session object. Keep the se_tpg and fabric_sess_ptr member variables as long as the session object exists. This patch fixes the following crash: general protection fault: 0000 [#1] SMP CPU: 5 PID: 15050 Comm: rmdir Tainted: G E 4.4.0-rc7+ #1 Hardware name: Dell Inc. PowerEdge R430/03XKDV, BIOS 1.0.2 11/17/2014 task: ffff880428349f40 ti: ffff880426584000 task.ti: ffff880426584000 RIP: 0010:[<ffffffff8126ef7d>] [<ffffffff8126ef7d>] __list_del_entry+0x2d/0xd0 RSP: 0018:ffff880426587cd8 EFLAGS: 00010a83 RAX: 6b6b6b6b6b6b6b6b RBX: ffff8804273687c0 RCX: dead000000000200 RDX: 6b6b6b6b6b6b6b6b RSI: ffff88042834ab20 RDI: ffff8804273687c0 RBP: ffff880426587ce8 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000001 R11: 0000000000000000 R12: ffff880426587d48 R13: ffff88041fc66a30 R14: 6b6b6b6b6b6b6b2b R15: ffff880427368780 FS: 00007f8b4ad54700(0000) GS:ffff88046e4a0000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007fec7ed44000 CR3: 0000000075a30000 CR4: 00000000001406e0 Stack: ffff88041fc66a30 ffff880427368780 ffff880426587d08 ffffffff8126f031 ffff880426587d08 ffff880422106618 ffff880426587d98 ffffffffa04f8390 ffff88045e5271b8 0000000000000000 ffff880426587d48 ffff880400000001 Call Trace: [<ffffffff8126f031>] list_del+0x11/0x40 [<ffffffffa04f8390>] core_tpg_del_initiator_node_acl+0x110/0x200 [target_core_mod] [<ffffffffa04ebcaf>] target_fabric_nacl_base_release+0x4f/0x60 [target_core_mod] [<ffffffffa0482bef>] config_item_release+0x6f/0xc0 [configfs] [<ffffffffa0482c5b>] config_item_put+0x1b/0x20 [configfs] [<ffffffffa0481f88>] configfs_rmdir+0x1e8/0x2e0 [configfs] [<ffffffff81183461>] vfs_rmdir+0x81/0x120 [<ffffffff81187246>] do_rmdir+0x146/0x190 [<ffffffff811872d1>] SyS_rmdir+0x11/0x20 [<ffffffff8151c857>] entry_SYSCALL_64_fastpath+0x12/0x6f Signed-off-by: Bart Van Assche <bart.vanassche@xxxxxxxxxxx> Cc: Christoph Hellwig <hch@xxxxxx> Cc: Andy Grover <agrover@xxxxxxxxxx> Cc: Sagi Grimberg <sagig@xxxxxxxxxxxx> --- drivers/target/target_core_transport.c | 27 ++++++++++++++++++++------- include/target/target_core_base.h | 1 + 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 6bb712f..e41dba5 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -240,6 +240,8 @@ struct se_session *transport_init_session(enum target_prot_op sup_prot_ops) INIT_LIST_HEAD(&se_sess->sess_wait_list); spin_lock_init(&se_sess->sess_cmd_lock); kref_init(&se_sess->sess_kref); + kref_init(&se_sess->kref2); + kref_get(&se_sess->kref2); se_sess->sup_prot_ops = sup_prot_ops; return se_sess; @@ -375,6 +377,18 @@ void transport_register_session( } EXPORT_SYMBOL(transport_register_session); +static void target_release_session2(struct kref *kref) +{ + struct se_session *sess = container_of(kref, typeof(*sess), kref2); + + transport_free_session(sess); +} + +static void target_put_session2(struct se_session *sess) +{ + kref_put(&sess->kref2, target_release_session2); +} + static void target_release_session(struct kref *kref) { struct se_session *se_sess = container_of(kref, @@ -382,6 +396,7 @@ static void target_release_session(struct kref *kref) struct se_portal_group *se_tpg = se_sess->se_tpg; se_tpg->se_tpg_tfo->close_session(se_sess); + target_put_session2(se_sess); } void target_get_session(struct se_session *se_sess) @@ -480,16 +495,13 @@ void transport_deregister_session(struct se_session *se_sess) unsigned long flags; bool comp_nacl = true, drop_nacl = false; - if (!se_tpg) { - transport_free_session(se_sess); - return; - } + if (!se_tpg) + goto put; + se_tfo = se_tpg->se_tpg_tfo; spin_lock_irqsave(&se_tpg->session_lock, flags); list_del(&se_sess->sess_list); - se_sess->se_tpg = NULL; - se_sess->fabric_sess_ptr = NULL; spin_unlock_irqrestore(&se_tpg->session_lock, flags); /* @@ -523,7 +535,8 @@ void transport_deregister_session(struct se_session *se_sess) if (se_nacl && comp_nacl) target_put_nacl(se_nacl); - transport_free_session(se_sess); +put: + target_put_session2(se_sess); } EXPORT_SYMBOL(transport_deregister_session); diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index ec368e9..ba203c2 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -611,6 +611,7 @@ struct se_session { struct list_head sess_wait_list; spinlock_t sess_cmd_lock; struct kref sess_kref; + struct kref kref2; void *sess_cmd_map; struct percpu_ida sess_tag_pool; }; -- 2.1.4 -- To unsubscribe from this list: send the line "unsubscribe target-devel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html