Message ID | 1524652133-7432-1-git-send-email-idryomov@gmail.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Wed, Apr 25, 2018 at 6:28 AM, Ilya Dryomov <idryomov@gmail.com> wrote: > ceph_con_workfn() validates con->state before calling try_read() and > then try_write(). However, try_read() temporarily releases con->mutex, > notably in process_message() and ceph_con_in_msg_alloc(), opening the > window for ceph_con_close() to sneak in, close the connection and > release con->sock. When try_write() is called on the assumption that > con->state is still valid (i.e. not STANDBY or CLOSED), a NULL sock > gets passed to the networking stack: > > BUG: unable to handle kernel NULL pointer dereference at 0000000000000020 > IP: selinux_socket_sendmsg+0x5/0x20 > > Make sure con->state is valid at the top of try_write() and add an > explicit BUG_ON for this, similar to try_read(). > > Cc: stable@vger.kernel.org > Link: https://tracker.ceph.com/issues/23706 > Signed-off-by: Ilya Dryomov <idryomov@gmail.com> > --- > net/ceph/messenger.c | 6 ++++++ > 1 file changed, 6 insertions(+) > > diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c > index fcb40c12b1f8..a7bfc07d2876 100644 > --- a/net/ceph/messenger.c > +++ b/net/ceph/messenger.c > @@ -2569,6 +2569,10 @@ static int try_write(struct ceph_connection *con) > int ret = 1; > > dout("try_write start %p state %lu\n", con, con->state); > + if (con->state != CON_STATE_PREOPEN && > + con->state != CON_STATE_NEGOTIATING && > + con->state != CON_STATE_OPEN) > + return 0; > > more: > dout("try_write out_kvec_bytes %d\n", con->out_kvec_bytes); > @@ -2594,6 +2598,8 @@ static int try_write(struct ceph_connection *con) > } > > more_kvec: > + BUG_ON(!con->sock); > + > /* kvec data queued? */ > if (con->out_kvec_left) { > ret = write_partial_kvec(con); > -- > 2.4.3 > > -- > To unsubscribe from this list: send the line "unsubscribe ceph-devel" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html Reviewed-by: Jason Dillaman <dillaman@redhat.com>
diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index fcb40c12b1f8..a7bfc07d2876 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -2569,6 +2569,10 @@ static int try_write(struct ceph_connection *con) int ret = 1; dout("try_write start %p state %lu\n", con, con->state); + if (con->state != CON_STATE_PREOPEN && + con->state != CON_STATE_NEGOTIATING && + con->state != CON_STATE_OPEN) + return 0; more: dout("try_write out_kvec_bytes %d\n", con->out_kvec_bytes); @@ -2594,6 +2598,8 @@ static int try_write(struct ceph_connection *con) } more_kvec: + BUG_ON(!con->sock); + /* kvec data queued? */ if (con->out_kvec_left) { ret = write_partial_kvec(con);
ceph_con_workfn() validates con->state before calling try_read() and then try_write(). However, try_read() temporarily releases con->mutex, notably in process_message() and ceph_con_in_msg_alloc(), opening the window for ceph_con_close() to sneak in, close the connection and release con->sock. When try_write() is called on the assumption that con->state is still valid (i.e. not STANDBY or CLOSED), a NULL sock gets passed to the networking stack: BUG: unable to handle kernel NULL pointer dereference at 0000000000000020 IP: selinux_socket_sendmsg+0x5/0x20 Make sure con->state is valid at the top of try_write() and add an explicit BUG_ON for this, similar to try_read(). Cc: stable@vger.kernel.org Link: https://tracker.ceph.com/issues/23706 Signed-off-by: Ilya Dryomov <idryomov@gmail.com> --- net/ceph/messenger.c | 6 ++++++ 1 file changed, 6 insertions(+)