Index | Thread | Search

From:
CypherFox <openbsd@cypher-fox.com>
Subject:
FIX: memory leak in relayd(8) config_purge
To:
tech@openbsd.org
Date:
Tue, 31 Mar 2026 01:01:18 +0200

Download raw body.

Thread
  • CypherFox:

    FIX: memory leak in relayd(8) config_purge

Hello,

I found a memory leak in relayd's config_purge() when handling 
CONFIG_PROTOS.
The current implementation uses two separate loops: the first one 
empties the
sc_protos list, which causes the second loop (responsible for the actual
free() calls) to be skipped entirely.

I've verified this with lldb. The second loop is never entered because
TAILQ_FIRST(env->sc_protos) returns NULL after the first loop finishes,
leaving the protocol structures and their members orphaned in the heap:


(lldb) p *env->sc_protos
(protolist) {
   tqh_first = NULL
   tqh_last = 0x000007fcaf00ee30
}
(lldb) p *env->sc_protos->tqh_last
(protocol *) NULL
(lldb) p ((struct protocol *)0x000007fc3db03000)->tlscapass
(char *) 0x000007fcaf003360 "s3cr3t"


This patch unifies the logic into a single loop to ensure all resources 
(rules, tlscerts, styles, and the protocol structure) are properly freed.


Index: usr.sbin/relayd/config.c
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/config.c,v
diff -u -p -u -p -r1.48 config.c
--- usr.sbin/relayd/config.c	2 Mar 2026 19:28:01 -0000	1.48
+++ usr.sbin/relayd/config.c	30 Mar 2026 21:47:03 -0000
@@ -186,19 +186,13 @@ config_purge(struct relayd *env, u_int r
  			while ((rule = TAILQ_FIRST(&proto->rules)) != NULL)
  				rule_delete(&proto->rules, rule);
  			proto->rulecount = 0;
-		}
-	}
-	if (what & CONFIG_PROTOS && env->sc_protos != NULL) {
-		while ((proto = TAILQ_FIRST(env->sc_protos)) != NULL) {
-			TAILQ_REMOVE(env->sc_protos, proto, entry);
-			free(proto->style);
-			free(proto->tlscapass);
-			while ((keyname =
-			    TAILQ_FIRST(&proto->tlscerts)) != NULL) {
+			while ((keyname = TAILQ_FIRST(&proto->tlscerts)) != NULL) {
  				TAILQ_REMOVE(&proto->tlscerts, keyname, entry);
  				free(keyname->name);
  				free(keyname);
  			}
+			free(proto->style);
+			free(proto->tlscapass);
  			free(proto);
  		}
  		env->sc_protocount = 0;