]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
libceph: validate con->state at the top of try_write()
authorIlya Dryomov <idryomov@gmail.com>
Tue, 24 Apr 2018 17:10:55 +0000 (19:10 +0200)
committerSasha Levin <alexander.levin@microsoft.com>
Wed, 23 May 2018 01:36:39 +0000 (21:36 -0400)
[ Upstream commit 9c55ad1c214d9f8c4594ac2c3fa392c1c32431a7 ]

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>
Reviewed-by: Jason Dillaman <dillaman@redhat.com>
Signed-off-by: Sasha Levin <alexander.levin@microsoft.com>
net/ceph/messenger.c

index d30864a8ed57febaff52da25ffd94469d7abc686..1e08c25c43f34aaa96d72a8adfbc78a239e38869 100644 (file)
@@ -2518,6 +2518,11 @@ 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_CONNECTING &&
+           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);
@@ -2543,6 +2548,8 @@ more:
        }
 
 more_kvec:
+       BUG_ON(!con->sock);
+
        /* kvec data queued? */
        if (con->out_kvec_left) {
                ret = write_partial_kvec(con);