]> git.apps.os.sepia.ceph.com Git - ceph.git/commit
osdc: Objecter::linger_by_cookie() for safe cast from uint64 65698/head
authorCasey Bodley <cbodley@redhat.com>
Fri, 26 Sep 2025 21:25:53 +0000 (17:25 -0400)
committerCasey Bodley <cbodley@redhat.com>
Fri, 26 Sep 2025 22:11:49 +0000 (18:11 -0400)
commit94f42b648feea77bd09dc3fdb48e6db2b48c7717
tree2a3f4fd971a022b5895a639d80fb8c284ca2634e
parent2455a713d44babf979b55832dc6f75363357d270
osdc: Objecter::linger_by_cookie() for safe cast from uint64

a `linger_ops_set` was added for `Objecter::handle_watch_notify()`
as a safety check before casting `uint64_t cookie` to `LingerOp*`
and deferencing it

neorados also made use of this set through `Objecter::is_valid_watch()`
checks. however, this approach was still susceptible to use-after-free,
because the callers didn't preserve a LingerOp reference between this
check and its use - and the Objecter lock is dropped in between. in
addition, `neorados::RADOS::unwatch_()` was missing its check for
`is_valid_watch()`

librados did not make use of this `is_valid_watch()` at all, so was
casting cookies directly to LingerOp* and dereferencing. this results
in use-after-free for any cookies invalidated by `linger_cancel()` -
for example when called by `CB_DoWatchError`

replace `is_valid_watch()` with a `linger_by_cookie()` function that
* performs the validity check with `linger_ops_set`,
* safely reinterpret_casts the cookie to LingerOp*, and
* returns a reference to the caller via intrusive_ptr<LingerOp>

`librados::IoCtxImpl::watch_check()`, `unwatch()` and `aio_unwatch()`
now call `linger_by_cookie()`, so have to handle the null case by
returning `-ENOTCONN` (this matches neorados' existing behavior)

Fixes: https://tracker.ceph.com/issues/72771
Signed-off-by: Casey Bodley <cbodley@redhat.com>
src/librados/IoCtxImpl.cc
src/neorados/RADOS.cc
src/osdc/Objecter.cc
src/osdc/Objecter.h