linux-stable/include/linux/ceph
Ilya Dryomov 8ceca1a069 libceph: fix potential use-after-free on linger ping and resends
commit 75dbb685f4 upstream.

request_reinit() is not only ugly as the comment rightfully suggests,
but also unsafe.  Even though it is called with osdc->lock held for
write in all cases, resetting the OSD request refcount can still race
with handle_reply() and result in use-after-free.  Taking linger ping
as an example:

    handle_timeout thread                     handle_reply thread

                                              down_read(&osdc->lock)
                                              req = lookup_request(...)
                                              ...
                                              finish_request(req)  # unregisters
                                              up_read(&osdc->lock)
                                              __complete_request(req)
                                                linger_ping_cb(req)

      # req->r_kref == 2 because handle_reply still holds its ref

    down_write(&osdc->lock)
    send_linger_ping(lreq)
      req = lreq->ping_req  # same req
      # cancel_linger_request is NOT
      # called - handle_reply already
      # unregistered
      request_reinit(req)
        WARN_ON(req->r_kref != 1)  # fires
        request_init(req)
          kref_init(req->r_kref)

                   # req->r_kref == 1 after kref_init

                                              ceph_osdc_put_request(req)
                                                kref_put(req->r_kref)

            # req->r_kref == 0 after kref_put, req is freed

        <further req initialization/use> !!!

This happens because send_linger_ping() always (re)uses the same OSD
request for watch ping requests, relying on cancel_linger_request() to
unregister it from the OSD client and rip its messages out from the
messenger.  send_linger() does the same for watch/notify registration
and watch reconnect requests.  Unfortunately cancel_request() doesn't
guarantee that after it returns the OSD client would be completely done
with the OSD request -- a ref could still be held and the callback (if
specified) could still be invoked too.

The original motivation for request_reinit() was inability to deal with
allocation failures in send_linger() and send_linger_ping().  Switching
to using osdc->req_mempool (currently only used by CephFS) respects that
and allows us to get rid of request_reinit().

Cc: stable@vger.kernel.org
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Reviewed-by: Xiubo Li <xiubli@redhat.com>
Acked-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2022-05-25 09:17:56 +02:00
..
auth.h
buffer.h libceph: allow ceph_buffer_put() to receive a NULL ceph_buffer 2019-08-22 10:47:41 +02:00
ceph_debug.h
ceph_features.h libceph: add __maybe_unused to DEFINE_CEPH_FEATURE 2020-08-24 10:33:08 +02:00
ceph_frag.h
ceph_fs.h ceph: periodically send perf metrics to MDSes 2020-08-03 11:05:26 +02:00
ceph_hash.h
cls_lock_client.h rbd: support for object-map and fast-diff 2019-07-08 14:01:45 +02:00
debugfs.h libceph: drop CEPH_DEFINE_SHOW_FUNC 2020-03-30 12:42:40 +02:00
decode.h libceph: rename ceph_encode_addr to ceph_encode_banner_addr 2019-07-08 14:01:43 +02:00
libceph.h ceph: move sb->wb_pagevec_pool to be a global mempool 2020-08-04 19:41:12 +02:00
mdsmap.h ceph: add possible_max_rank and make the code more readable 2020-01-27 16:53:40 +01:00
messenger.h libceph: fix ENTITY_NAME format suggestion 2020-10-12 15:29:27 +02:00
mon_client.h libceph, rbd, ceph: "blacklist" -> "blocklist" 2020-10-12 15:29:26 +02:00
msgpool.h libceph: preallocate message data items 2018-10-22 10:28:22 +02:00
msgr.h
osd_client.h libceph: fix potential use-after-free on linger ping and resends 2022-05-25 09:17:56 +02:00
osdmap.h libceph: multiple workspaces for CRUSH computations 2020-10-12 15:29:26 +02:00
pagelist.h libceph: introduce ceph_pagelist_alloc() 2018-10-22 10:28:21 +02:00
rados.h libceph, rbd, ceph: "blacklist" -> "blocklist" 2020-10-12 15:29:26 +02:00
string_table.h
striper.h rbd: support for object-map and fast-diff 2019-07-08 14:01:45 +02:00
types.h ceph: add mount option to limit caps count 2019-03-05 18:55:17 +01:00