Files
linux-bredos/include/linux
Ilya Dryomov 75dbb685f4 libceph: fix potential use-after-free on linger ping and resends
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>
2022-05-18 21:21:05 +02:00
..
2022-02-27 13:38:10 +00:00
2022-03-23 19:58:38 +01:00
2022-02-01 14:25:50 +02:00
2022-03-17 20:17:18 -07:00
2022-03-11 19:15:03 -08:00
2022-03-15 10:32:44 +01:00
2022-02-07 16:35:35 -08:00
2022-03-16 15:13:36 -07:00
2022-02-13 16:50:07 -08:00
2022-04-01 14:40:44 -04:00
2022-04-07 09:43:41 -04:00
2022-03-02 22:44:49 -08:00
2022-02-28 23:26:27 -08:00
2022-03-15 08:23:29 -04:00
2022-02-28 13:25:49 +01:00
2022-02-19 19:23:53 -08:00
2022-02-14 15:43:15 +01:00
2022-02-05 15:20:34 +00:00
2022-03-18 09:47:04 +01:00
2022-03-21 12:57:38 -04:00
2022-04-01 14:40:44 -04:00
2022-02-09 09:24:40 -05:00
2022-02-28 13:45:04 +02:00
2022-03-24 19:06:45 -07:00
2022-04-01 13:45:08 -04:00
2022-02-02 07:49:59 -07:00
2022-02-09 08:04:44 +01:00
2022-02-09 08:04:44 +01:00
2022-04-19 10:19:02 -07:00
2022-03-08 14:33:36 -06:00
2022-03-17 20:16:29 -07:00
2022-03-23 19:58:41 +01:00
2022-02-24 15:04:51 +00:00
2022-02-25 09:36:06 +01:00
2022-04-11 19:18:27 -06:00
2022-02-16 07:49:41 +01:00
2022-03-22 15:57:11 -07:00
2022-03-28 16:53:00 -04:00