forked from Minki/linux
staging: lustre: separate a connection destroy from free struct kib_conn
The logic of the original commit4d99b2581e
("staging: lustre: avoid intensive reconnecting for ko2iblnd") was assumed conditional free of struct kib_conn if the second argument free_conn in function kiblnd_destroy_conn(struct kib_conn *conn, bool free_conn) is true. But this hunk of code was dropped from original commit. As result the logic works wrong and current code use struct kib_conn after free. > drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c > 3317 kiblnd_destroy_conn(conn, !peer); > ^^^^ Freed always (but should be conditionally) > 3318 > 3319 spin_lock_irqsave(lock, flags); > 3320 if (!peer) > 3321 continue; > 3322 > 3323 conn->ibc_peer = peer; > ^^^^^^^^^^^^^^ Use after free > 3324 if (peer->ibp_reconnected < KIB_RECONN_HIGH_RACE) > 3325 list_add_tail(&conn->ibc_list, > ^^^^^^^^^^^^^^ Use after free > 3326 &kiblnd_data.kib_reconn_list); > 3327 else > 3328 list_add_tail(&conn->ibc_list, > ^^^^^^^^^^^^^^ Use after free > 3329 &kiblnd_data.kib_reconn_wait); To avoid confusion this fix moved the freeing a struct kib_conn outside of the function kiblnd_destroy_conn() and free as it was intended in original commit. Cc: <stable@vger.kernel.org> # v4.6 Fixes:4d99b2581e
("staging: lustre: avoid intensive reconnecting for ko2iblnd") Signed-off-by: Dmitry Eremin <Dmitry.Eremin@intel.com> Reviewed-by: Andreas Dilger <andreas.dilger@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
9d03032d30
commit
9b046013e5
@ -824,14 +824,15 @@ struct kib_conn *kiblnd_create_conn(struct kib_peer *peer, struct rdma_cm_id *cm
|
||||
return conn;
|
||||
|
||||
failed_2:
|
||||
kiblnd_destroy_conn(conn, true);
|
||||
kiblnd_destroy_conn(conn);
|
||||
kfree(conn);
|
||||
failed_1:
|
||||
kfree(init_qp_attr);
|
||||
failed_0:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void kiblnd_destroy_conn(struct kib_conn *conn, bool free_conn)
|
||||
void kiblnd_destroy_conn(struct kib_conn *conn)
|
||||
{
|
||||
struct rdma_cm_id *cmid = conn->ibc_cmid;
|
||||
struct kib_peer *peer = conn->ibc_peer;
|
||||
@ -889,8 +890,6 @@ void kiblnd_destroy_conn(struct kib_conn *conn, bool free_conn)
|
||||
rdma_destroy_id(cmid);
|
||||
atomic_dec(&net->ibn_nconns);
|
||||
}
|
||||
|
||||
kfree(conn);
|
||||
}
|
||||
|
||||
int kiblnd_close_peer_conns_locked(struct kib_peer *peer, int why)
|
||||
|
@ -1016,7 +1016,7 @@ int kiblnd_close_peer_conns_locked(struct kib_peer *peer, int why);
|
||||
struct kib_conn *kiblnd_create_conn(struct kib_peer *peer,
|
||||
struct rdma_cm_id *cmid,
|
||||
int state, int version);
|
||||
void kiblnd_destroy_conn(struct kib_conn *conn, bool free_conn);
|
||||
void kiblnd_destroy_conn(struct kib_conn *conn);
|
||||
void kiblnd_close_conn(struct kib_conn *conn, int error);
|
||||
void kiblnd_close_conn_locked(struct kib_conn *conn, int error);
|
||||
|
||||
|
@ -3314,11 +3314,13 @@ kiblnd_connd(void *arg)
|
||||
spin_unlock_irqrestore(lock, flags);
|
||||
dropped_lock = 1;
|
||||
|
||||
kiblnd_destroy_conn(conn, !peer);
|
||||
kiblnd_destroy_conn(conn);
|
||||
|
||||
spin_lock_irqsave(lock, flags);
|
||||
if (!peer)
|
||||
if (!peer) {
|
||||
kfree(conn);
|
||||
continue;
|
||||
}
|
||||
|
||||
conn->ibc_peer = peer;
|
||||
if (peer->ibp_reconnected < KIB_RECONN_HIGH_RACE)
|
||||
|
Loading…
Reference in New Issue
Block a user