File: core-no-longer-supply-bogus-services-to-callbacks.patch

package info (click to toggle)
avahi 0.8-16
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 10,700 kB
  • sloc: ansic: 40,980; sh: 6,061; xml: 4,594; cs: 2,185; makefile: 1,742; python: 441; cpp: 224; sed: 16
file content (159 lines) | stat: -rw-r--r-- 6,749 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
From: Evgeny Vereshchagin <evvers@ya.ru>
Date: Sun, 12 Nov 2023 01:16:58 +0000
Subject: core: no longer supply bogus services to callbacks

It was technically a DOS allowing packets with service names like
"bogus.service.local" to bring down `avahi-browse -a`. In practice
it was usually triggered by misconfigured smart devices but it isn't
that hard to forge packets like that and send them deliberately.

The tests are added to make sure invalid service names are rejected and
valid service names keep working. The fuzz target is updated to make
sure that avahi_service_name_split always supplies valid arguments to
avahi_service_name_join. avahi now logs what exactly it fails to split
```
avahi-daemon[176]: Failed to split service name '0.1.9.1.8.8.e.f.f.f.f.a.a.1.4.7.0.0.0.0.0.0.0.0.0.0.0.0.0.8.e.f.ip6.arpa'
avahi-daemon[176]: Failed to split service name 'bogus\032.\032\209\129\208\181\209\128\208\178\208\184\209\129.local'
avahi-daemon[176]: Failed to split service name '255.20.254.169.in-addr.arpa'
avahi-daemon[176]: Failed to split service name 'bogus\032.\032\209\129\208\181\209\128\208\178\208\184\209\129.local'
avahi-daemon[176]: Failed to split service name '33.93.168.192.in-addr.arpa'
```
when --debug is passed to it (which makes that part consistent with the
other places where weird packets are rejected).

Closes https://github.com/lathiat/avahi/issues/212

(cherry picked from commit 93b14365c1c1e04efd1a890e8caa01a2a514bfd8)
Origin: https://github.com/avahi/avahi/commit/93b14365c1c1e04efd1a890e8caa01a2a514bfd8
---
 avahi-common/domain-test.c       | 36 ++++++++++++++++++++++++++++++++++++
 avahi-common/domain.c            | 14 ++++++++++++++
 avahi-core/browse-service-type.c |  2 +-
 avahi-core/browse-service.c      |  2 +-
 4 files changed, 52 insertions(+), 2 deletions(-)

diff --git a/avahi-common/domain-test.c b/avahi-common/domain-test.c
index 3acc1c1..22ca430 100644
--- a/avahi-common/domain-test.c
+++ b/avahi-common/domain-test.c
@@ -26,6 +26,7 @@
 #include <assert.h>
 
 #include "domain.h"
+#include "error.h"
 #include "malloc.h"
 
 int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char *argv[]) {
@@ -34,6 +35,7 @@ int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char *argv[]) {
     const char *p;
     size_t size;
     char name[64], type[AVAHI_DOMAIN_NAME_MAX], domain[AVAHI_DOMAIN_NAME_MAX];
+    int res;
 
     printf("%s\n", s = avahi_normalize_name_strdup("foo.foo\\046."));
     avahi_free(s);
@@ -133,5 +135,39 @@ int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char *argv[]) {
     assert(!avahi_is_valid_fqdn("::1"));
     assert(!avahi_is_valid_fqdn(".192.168.50.1."));
 
+    res = avahi_service_name_split("test._ssh._tcp.local", name, sizeof(name), type, sizeof(type), domain, sizeof(domain));
+    assert(res >= 0);
+    assert(strcmp(name, "test") == 0);
+    assert(strcmp(type, "_ssh._tcp") == 0);
+    assert(strcmp(domain, "local") == 0);
+
+    res = avahi_service_name_split("test._hop._sub._ssh._tcp.local", name, sizeof(name), type, sizeof(type), domain, sizeof(domain));
+    assert(res >= 0);
+    assert(strcmp(name, "test") == 0);
+    assert(strcmp(type, "_hop._sub._ssh._tcp") == 0);
+    assert(strcmp(domain, "local") == 0);
+
+    res = avahi_service_name_split("_qotd._udp.hey.local", NULL, 0, type, sizeof(type), domain, sizeof(domain));
+    assert(res >= 0);
+    assert(strcmp(type, "_qotd._udp") == 0);
+    assert(strcmp(domain, "hey.local") == 0);
+
+    res = avahi_service_name_split("_wat._sub._qotd._udp.hey.local", NULL, 0, type, sizeof(type), domain, sizeof(domain));
+    assert(res >= 0);
+    assert(strcmp(type, "_wat._sub._qotd._udp") == 0);
+    assert(strcmp(domain, "hey.local") == 0);
+
+    res = avahi_service_name_split("wat.bogus.service.local", name, sizeof(name), type, sizeof(type), domain, sizeof(domain));
+    assert(res == AVAHI_ERR_INVALID_SERVICE_TYPE);
+
+    res = avahi_service_name_split("bogus.service.local", NULL, 0, type, sizeof(type), domain, sizeof(domain));
+    assert(res == AVAHI_ERR_INVALID_SERVICE_TYPE);
+
+    res = avahi_service_name_split("", name, sizeof(name), type, sizeof(type), domain, sizeof(domain));
+    assert(res == AVAHI_ERR_INVALID_SERVICE_NAME);
+
+    res = avahi_service_name_split("", NULL, 0, type, sizeof(type), domain, sizeof(domain));
+    assert(res == AVAHI_ERR_INVALID_SERVICE_TYPE);
+
     return 0;
 }
diff --git a/avahi-common/domain.c b/avahi-common/domain.c
index e66d241..795b4fd 100644
--- a/avahi-common/domain.c
+++ b/avahi-common/domain.c
@@ -500,6 +500,7 @@ int avahi_service_name_split(const char *p, char *name, size_t name_size, char *
         DOMAIN
     } state;
     int type_empty = 1, domain_empty = 1;
+    char *oname, *otype, *odomain;
 
     assert(p);
     assert(type);
@@ -507,6 +508,10 @@ int avahi_service_name_split(const char *p, char *name, size_t name_size, char *
     assert(domain);
     assert(domain_size > 0);
 
+    oname = name;
+    otype = type;
+    odomain = domain;
+
     if (name) {
         assert(name_size > 0);
         *name = 0;
@@ -569,6 +574,15 @@ int avahi_service_name_split(const char *p, char *name, size_t name_size, char *
         }
     }
 
+    if ((oname && !avahi_is_valid_service_name(oname)))
+        return AVAHI_ERR_INVALID_SERVICE_NAME;
+
+    if (!avahi_is_valid_service_type_generic(otype))
+        return AVAHI_ERR_INVALID_SERVICE_TYPE;
+
+    if (!avahi_is_valid_domain_name(odomain))
+        return AVAHI_ERR_INVALID_DOMAIN_NAME;
+
     return 0;
 }
 
diff --git a/avahi-core/browse-service-type.c b/avahi-core/browse-service-type.c
index b1fc7af..f0d6938 100644
--- a/avahi-core/browse-service-type.c
+++ b/avahi-core/browse-service-type.c
@@ -65,7 +65,7 @@ static void record_browser_callback(
         assert(record->key->type == AVAHI_DNS_TYPE_PTR);
 
         if (avahi_service_name_split(record->data.ptr.name, NULL, 0, type, sizeof(type), domain, sizeof(domain)) < 0) {
-            avahi_log_warn("Invalid service type '%s'", record->key->name);
+            avahi_log_debug("Failed to split service name '%s'", record->data.ptr.name);
             return;
         }
 
diff --git a/avahi-core/browse-service.c b/avahi-core/browse-service.c
index 63e0275..e924bae 100644
--- a/avahi-core/browse-service.c
+++ b/avahi-core/browse-service.c
@@ -69,7 +69,7 @@ static void record_browser_callback(
             flags |= AVAHI_LOOKUP_RESULT_LOCAL;
 
         if (avahi_service_name_split(record->data.ptr.name, service, sizeof(service), type, sizeof(type), domain, sizeof(domain)) < 0) {
-            avahi_log_warn("Failed to split '%s'", record->key->name);
+            avahi_log_debug("Failed to split service name '%s'", record->data.ptr.name);
             return;
         }