chenBright opened a new pull request, #3487:
URL: https://github.com/apache/brpc/pull/3487

   ### What problem does this PR solve?
   
   Issue Number: resolve 
   
   Problem Summary:
   
   bvar sampling has two lifetime hazards, both of which end up as a silent
   use-after-free:
   
   1. `detail::ReducerSampler` holds a raw `R* _reducer` and dereferences it in
      `take_sample()` and `get_value()`. Safety therefore relies entirely on 
every
      host correctly calling `Sampler::destroy()` from its dtor, which is a 
convention,
      not a structural guarantee.
   
   2. `Window`/`PerSecond` borrow the sampler of the bvar they reference
      (`var->get_sampler()`), and `WindowBase::SeriesSampler::Op` holds a raw
      `R* _var`. If a Window outlives that bvar (violating the contract 
documented
      in `bvar/window.h`), the sampling thread has already `delete`d the 
sampler, so
      the Window is left with a permanently dangling pointer: both 
`get_value()` and 
      the series sampler become a use-after-free, and nothing reports the 
misuse.
   
   ### What is changed and the side effects?
   
   Changed:
   
   1. Sample through the shared data carrier where possible.
   `ReducerSampler` now selects its data source with a trait: hosts exposing
   `share_combiner()` are sampled through their `shared_ptr<AgentCombiner>` plus
   by-value copies of `Op`/`InvOp`, so the sampler never dereferences the host 
after
   construction. Since the sampler keeps a reference to the combiner, sampling 
reads
   valid memory even if the host is destructed before the sampler is recycled.
   `share_combiner()` is added to `Reducer` (Adder/Maxer/Miner), `IntRecorder` 
and
   `Percentile` (the one inside `LatencyRecorder`). Hosts without such a 
carrier --
   `PassiveStatus` (data lives in a user callback) and the babylon variants 
(value
   types) -- keep the previous host-pointer mode, so their behaviour is 
unchanged.
   
   2. Detect a Window outliving its bvar, and degrade UAF to a bounded leak.
   `Sampler` gains a borrower counter (guarded by its existing `_mutex`) with
   `add_borrower()`/`remove_borrower()`, called by `WindowBase`'s ctor/dtor. If
   `destroy()` finds the sampler still borrowed, it reports the misuse 
(including
   the bvar name) and marks the sampler, and the sampling thread then skips the
   `delete`, leaking it on purpose. The borrowers keep pointing at valid memory
   and merely stop receiving new samples. Note the counter and the "don't 
delete"
   part are inseparable: otherwise `remove_borrower()` itself would be a
   use-after-free. A new gflag `bvar_abort_on_sampler_still_borrowed` (default
   `false`, i.e. `LOG(ERROR)`) can escalate this to an abort, mirroring the 
existing
   `bvar_abort_on_same_name`.
   
   **3. Stop touching the var from the series sampler.**
   `WindowBase::SeriesSampler::Op` used to hold `R* _var` and call `_var->op()` 
from
   the sampling thread. It now holds a copy of the operator (bvar operators 
such as 
   `AddTo`/`MaxTo`/`AddStat` are stateless functors), copied once into 
`WindowBase::_var_op` 
   at construction. As a result `_var` is only dereferenced in the ctor and 
never afterwards.
   
   Side effects:
   - Performance effects:
   
   - Breaking backward compatibility: 
   
   ---
   ### Check List:
   - Please make sure your changes are compilable.
   - When providing us with a new feature, it is best to add related tests.
   - Please follow [Contributor Covenant Code of 
Conduct](https://github.com/apache/brpc/blob/master/CODE_OF_CONDUCT.md).


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to