git: dd5dc8f6e51c - main - epoch: Fix use-after-free in epoch_trace_report()
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Wed, 30 Sep 2026 13:51:27 UTC
The branch main has been updated by rcm:
URL: https://cgit.FreeBSD.org/src/commit/?id=dd5dc8f6e51c5132f2dc885f5c1b0492cdf3052c
commit dd5dc8f6e51c5132f2dc885f5c1b0492cdf3052c
Author: R. Christian McDonald <rcm@FreeBSD.org>
AuthorDate: 2026-09-30 13:41:53 +0000
Commit: R. Christian McDonald <rcm@FreeBSD.org>
CommitDate: 2026-09-30 13:51:18 +0000
epoch: Fix use-after-free in epoch_trace_report()
epoch_trace_report() assigned the return value of RB_INSERT() back to
the new element. When two threads report the same stack concurrently,
the loser's RB_INSERT() returns the element already in the tree, and
that element was freed while still linked, leaking the new allocation.
The next lookup touches freed memory; KASAN catches it as a
use-after-free.
Keep the return value separate and free the new element instead. The
thread that won the race prints the report, so return without printing
it a second time.
Reviewed by: markj
Fixes: 173c062a569b ("Improve EPOCH_TRACE")
MFC after: 1 week
Sponsored by: Rubicon Communications, LLC ("Netgate")
Differential Revision: https://reviews.freebsd.org/D60162
---
sys/kern/subr_epoch.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/sys/kern/subr_epoch.c b/sys/kern/subr_epoch.c
index 266230b04b43..e81b91295d48 100644
--- a/sys/kern/subr_epoch.c
+++ b/sys/kern/subr_epoch.c
@@ -193,6 +193,7 @@ epoch_trace_report(const char *fmt, ...)
{
va_list ap;
struct stackentry se, *new;
+ bool dup;
stack_save(&se.se_stack);
@@ -205,10 +206,13 @@ epoch_trace_report(const char *fmt, ...)
bcopy(&se.se_stack, &new->se_stack, sizeof(struct stack));
mtx_lock(&epoch_stacks_lock);
- new = RB_INSERT(stacktree, &epoch_stacks, new);
+ dup = RB_INSERT(stacktree, &epoch_stacks, new) != NULL;
mtx_unlock(&epoch_stacks_lock);
- if (new != NULL)
+ if (dup) {
+ /* Lost a race; the other thread reports it. */
free(new, M_STACK);
+ return;
+ }
}
va_start(ap, fmt);