Index | Thread | Search

From:
Carsten Beckmann <carsten_beckmann@genua.de>
Subject:
Fix potential use-after-free with srp_follow()
To:
"tech@openbsd.org" <tech@openbsd.org>
Date:
Wed, 29 Oct 2025 10:27:54 +0000

Download raw body.

Thread
Hi,

I was recently debugging a protection fault in a kernel based on OpenBSD 7.7.
Iterating over a SRP list with SRPL_FOREACH seemingly returned a corrupted
pointer. I did trace the issue down to a bug in the SRP implementation.

srp_follow() is supposed to replace the reference held by the given srp_ref with
a reference to the data structure that is represented by the given srp struct.
This process is not atomic though. The old reference is given up immediately in
srp_v() when one part of the hazard is updated with 'hzrd->sh_p = srp'.
Afterwards the srp struct is read to get the value represented by that struct.

This causes a problem when srp_follow() is used to iterate over SRP lists. The
current list element is only guaranteed to be kept alive while the hazard inside
the srp_ref still points to it. As soon as that reference is given up in the
call to srp_follow() the element may be freed. With SRP lists the srp struct
that is read afterwards lives inside of the current element though. Accessing it
to get a reference to the next list element can therefore be a use-after-free.

The fix is simple: Use srp_enter() to get a new reference to the next element
while keeping the current element alive. Afterwards the old reference can safely
be released and the hazard in the caller provided srp_ref struct can be updated
to the hazard of the new element.

diff --git sys/kern/kern_srp.c sys/kern/kern_srp.c
index c002fa391fd..7b702b9bde2 100644
--- sys/kern/kern_srp.c
+++ sys/kern/kern_srp.c
@@ -235,7 +235,14 @@ srp_enter(struct srp_ref *sr, struct srp *srp)
 void *
 srp_follow(struct srp_ref *sr, struct srp *srp)
 {
-	return (srp_v(sr->hz, srp));
+	struct srp_ref nsr;
+	void *nv;
+
+	nv = srp_enter(&nsr, srp);
+	srp_leave(sr);
+	sr->hz = nsr.hz;
+
+	return (nv);
 }
 
 void