From 5eea2640324928c15936b7a2bcbf8ea0de7b08f7 Mon Sep 17 00:00:00 2001
From: Hugo Muis <198191869+friendlyhugo@users.noreply.github.com>
Date: Sun, 2 Mar 2025 18:06:24 +0100
Subject: [PATCH] core: fix uncontrolled recursion bug using a simple loop
 detection algorithm

Closes https://github.com/avahi/avahi/issues/501

CVE: CVE-2026-24401
Upstream-Status: Backport [https://github.com/avahi/avahi/commit/78eab31128479f06e30beb8c1cbf99dd921e2524]
(cherry picked from commit 78eab31128479f06e30beb8c1cbf99dd921e2524)
Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
---
 avahi-core/browse.c | 40 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/avahi-core/browse.c b/avahi-core/browse.c
index f461083..975b3e9 100644
--- a/avahi-core/browse.c
+++ b/avahi-core/browse.c
@@ -401,6 +401,40 @@ static int lookup_go(AvahiSRBLookup *l) {
     return n;
 }
 
+static int lookup_exists_in_path(AvahiSRBLookup* lookup, AvahiSRBLookup* from, AvahiSRBLookup* to) {
+    AvahiRList* rl;
+    if (from == to)
+        return 0;
+    for (rl = from->cname_lookups; rl; rl = rl->rlist_next) {
+        int r = lookup_exists_in_path(lookup, rl->data, to);
+        if (r == 1) {
+            /* loop detected, propagate result */
+            return r;
+        } else if (r == 0) {
+            /* is loop detected? */
+            return lookup == from;
+        } else {
+	        /* `to` not found, continue */
+            continue;
+        }
+    }
+    /* no path found */
+    return -1;
+}
+
+static int cname_would_create_loop(AvahiSRBLookup* l, AvahiSRBLookup* n) {
+    int ret;
+    if (l == n)
+        /* Loop to self */
+        return 1;
+
+    ret = lookup_exists_in_path(n, l->record_browser->root_lookup, l);
+
+    /* Path to n always exists */
+    assert(ret != -1);
+    return ret;
+}
+
 static void lookup_handle_cname(AvahiSRBLookup *l, AvahiIfIndex interface, AvahiProtocol protocol, AvahiLookupFlags flags, AvahiRecord *r) {
     AvahiKey *k;
     AvahiSRBLookup *n;
@@ -420,6 +454,12 @@ static void lookup_handle_cname(AvahiSRBLookup *l, AvahiIfIndex interface, Avahi
         return;
     }
 
+    if (cname_would_create_loop(l, n)) {
+        /* CNAME loops are not allowed */
+        lookup_unref(n);
+        return;
+    }
+
     l->cname_lookups = avahi_rlist_prepend(l->cname_lookups, lookup_ref(n));
 
     lookup_go(n);
