When debugging use-after-free(UAF) bugs, knowing when the object reaches
0 references and enters final release(final put) can significantly aid the
debugging process.

This patch series adds a tracepoint, refcount_final_put, with
compilation toggleable with CONFIG_REFCOUNT_TRACE_FINAL_PUT.

refcount_final_put fires when a reference
count reaches zero and the object enters its final release path.

refcount_final_put records three fields:
- caller: function that called the refcounting
  function(refcount_sub_and_test, percpu_ref_put_many)
- ip: return address of trace wrapper macro call
- obj: refcount object(struct percpu_ref, refcount_t)

bloat-o-meter stats:

CONFIG_REFCOUNT_TRACE_FINAL_PUT=n :
Total: Before=24703933, After=24703933, chg +0.00%

CONFIG_REFCOUNT_TRACE_FINAL_PUT=y :
Total: Before=24703933, After=24764816, chg +0.25%

Alternatives to obtain this information require live reproduction, and
incur a significant performance cost, making them impractical to have
enabled on fuzzers like syzbot.

refcount functions performing final-puts are also inlined, further
complicating alternative dynamic tracing possibilities.

Debugging UAFs without final-put knowledge is possible but is often
significantly harder and requires broad code reading and mapping,
whereas knowing the final-put allows narrowing the scope, thus
decreasing time and effort required.

Local live reproduction and alternative tracing are time, hardware
resource, and manual effort exhaustive. Time-sensitive UAFs which
require many iterations to reproduce further worsen these requirements.

Remote-fuzzer report based UAF debugging is an incredibly frequent
occurence.

Signed-off-by: Eugene Mavick <[email protected]>
---
Changes in v5:
-rename ref_trace to refcount
-add CONFIG_REFCOUNT_TRACE_FINAL_PUT Kconfig option, due to high footprint
-improve cover letter, add bloat-o-meter statistics
v4: 
https://lore.kernel.org/r/[email protected]

Changes in v4:
ref-trace:
-remove fn
-add ip variable
-change trace wrapper macro respectively, _THIS_IP_ is used for ip variable
-change relevant code respect to fn removal and ip addition
-fix style issues in include/linux/ref_trace.h
-add new macro do_trace_ref_final_put_cond that only calls tracepoint if cond is
 true
lib/refcount.c:
-change from do_trace_ref_final_put to *_cond
-remove if statement above since _cond already performs the check
KUnit:
-change relevant code respect to fn removal and ip addition
-check if caller and ip are valid addresses
-change timeout from 10 jiffies to 10 seconds
-move didn't timeout assertion from before to after probe
 unregistration, to prevent it from impacting next test

Changes in v3:
include/trace/events/ref_trace.h kernel doc comments:
-caller of refcount function -> return address of refcount function
-ref_trace_final_put->do_ref_trace_final_put
lib/ref_trace.c: add include trace/events/ref_trace.h
kunit:
-change Kconfig depends from FTRACE->TRACEPOINTS
-EXPECT_FALSE->ASSERT_FALSE for calling percpu_ref_init
-add tracepoint_synchronise_unregister to test_exit macro
-added timeout to capture.count waiting
-remove noinline and __always_inline from function attributes
 (added for testing, but accidentally submitted)
-add period to the end of Kconfig help text
v2 link:
https://lore.kernel.org/all/[email protected]/

Changes in v2:
-include/linux/ref_trace.h: change macro name, use direct tracepoint
 call in macro to avoid double check
-add tracepoint to refcount_dec_if_one
-kunit: make significant improvements to design, fix critical bug, add test 
case for
 refcount_dec_if_one()
-Link to v1: 
https://lore.kernel.org/r/[email protected]

---
Eugene Mavick (5):
      tracing: add refcount_final_put tracepoint
      refcount: add refcount_final_put tracepoint
      percpu-refcount: add refcount_final_put tracepoint
      kunit: add test for refcount_final_put
      MAINTAINERS: add entries for refcount_final_put trace

 MAINTAINERS                      |   3 +
 include/linux/percpu-refcount.h  |   5 +-
 include/linux/refcount.h         |   2 +
 include/linux/refcount_trace.h   |  33 +++++++++
 include/trace/events/refcount.h  |  55 +++++++++++++++
 lib/Kconfig                      |  18 +++++
 lib/Makefile                     |   2 +
 lib/refcount.c                   |   6 +-
 lib/refcount_trace.c             |  14 ++++
 lib/tests/Makefile               |   1 +
 lib/tests/refcount_trace_kunit.c | 141 +++++++++++++++++++++++++++++++++++++++
 11 files changed, 278 insertions(+), 2 deletions(-)
---
base-commit: df685633c3dbc67441cc86f1c3fee58de4652ba2
change-id: 20260624-refcount-final-put-trace-49bd7c39bd5a

Best regards,
-- 
Eugene Mavick <[email protected]>


Reply via email to