Bug Summary

File:build-scan/../src/resolve/resolved-dns-question.c
Warning:line 256, column 33
Potential leak of memory pointed to by 'n'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name resolved-dns-question.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -menable-no-infs -menable-no-nans -menable-unsafe-fp-math -fno-signed-zeros -mreassociate -freciprocal-math -fdenormal-fp-math=preserve-sign,preserve-sign -ffp-contract=fast -fno-rounding-math -ffast-math -ffinite-math-only -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.0.0 -include config.h -I src/resolve/libsystemd-resolve-core.a.p -I src/resolve -I ../src/resolve -I src/basic -I ../src/basic -I src/shared -I ../src/shared -I src/systemd -I ../src/systemd -I src/journal -I ../src/journal -I src/journal-remote -I ../src/journal-remote -I src/nspawn -I ../src/nspawn -I src/timesync -I ../src/timesync -I ../src/time-wait-sync -I src/login -I ../src/login -I src/udev -I ../src/udev -I src/libudev -I ../src/libudev -I src/core -I ../src/core -I ../src/libsystemd/sd-bus -I ../src/libsystemd/sd-device -I ../src/libsystemd/sd-hwdb -I ../src/libsystemd/sd-id128 -I ../src/libsystemd/sd-netlink -I ../src/libsystemd/sd-network -I src/libsystemd-network -I ../src/libsystemd-network -I . -I .. -D _FILE_OFFSET_BITS=64 -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wwrite-strings -Wno-unused-parameter -Wno-missing-field-initializers -Wno-unused-result -Wno-format-signedness -Wno-error=nonnull -std=gnu99 -fconst-strings -fdebug-compilation-dir /home/mrc0mmand/repos/@redhat-plumbers/systemd-rhel8/build-scan -ferror-limit 19 -fvisibility hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -analyzer-output=html -faddrsig -o /tmp/scan-build-2021-07-16-221226-1465241-1 -x c ../src/resolve/resolved-dns-question.c
1/* SPDX-License-Identifier: LGPL-2.1+ */
2
3#include "alloc-util.h"
4#include "dns-domain.h"
5#include "dns-type.h"
6#include "resolved-dns-question.h"
7
8DnsQuestion *dns_question_new(size_t n) {
9 DnsQuestion *q;
10
11 assert(n > 0)do { if ((__builtin_expect(!!(!(n > 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("n > 0"), "../src/resolve/resolved-dns-question.c"
, 11, __PRETTY_FUNCTION__); } while (0)
;
23
Taking false branch
24
Loop condition is false. Exiting loop
12
13 q = malloc0(offsetof(DnsQuestion, keys) + sizeof(DnsResourceKey*) * n)(calloc(1, (__builtin_offsetof(DnsQuestion, keys) + sizeof(DnsResourceKey
*) * n)))
;
25
Memory is allocated
14 if (!q)
26
Assuming 'q' is non-null
27
Taking false branch
15 return NULL((void*)0);
16
17 q->n_ref = 1;
18 q->n_allocated = n;
19
20 return q;
21}
22
23DnsQuestion *dns_question_ref(DnsQuestion *q) {
24 if (!q)
25 return NULL((void*)0);
26
27 assert(q->n_ref > 0)do { if ((__builtin_expect(!!(!(q->n_ref > 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("q->n_ref > 0"), "../src/resolve/resolved-dns-question.c"
, 27, __PRETTY_FUNCTION__); } while (0)
;
28 q->n_ref++;
29 return q;
30}
31
32DnsQuestion *dns_question_unref(DnsQuestion *q) {
33 if (!q)
34 return NULL((void*)0);
35
36 assert(q->n_ref > 0)do { if ((__builtin_expect(!!(!(q->n_ref > 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("q->n_ref > 0"), "../src/resolve/resolved-dns-question.c"
, 36, __PRETTY_FUNCTION__); } while (0)
;
37
38 if (q->n_ref == 1) {
39 size_t i;
40
41 for (i = 0; i < q->n_keys; i++)
42 dns_resource_key_unref(q->keys[i]);
43 free(q);
44 } else
45 q->n_ref--;
46
47 return NULL((void*)0);
48}
49
50int dns_question_add(DnsQuestion *q, DnsResourceKey *key) {
51 size_t i;
52 int r;
53
54 assert(key)do { if ((__builtin_expect(!!(!(key)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("key"), "../src/resolve/resolved-dns-question.c"
, 54, __PRETTY_FUNCTION__); } while (0)
;
55
56 if (!q)
57 return -ENOSPC28;
58
59 for (i = 0; i < q->n_keys; i++) {
60 r = dns_resource_key_equal(q->keys[i], key);
61 if (r < 0)
62 return r;
63 if (r > 0)
64 return 0;
65 }
66
67 if (q->n_keys >= q->n_allocated)
68 return -ENOSPC28;
69
70 q->keys[q->n_keys++] = dns_resource_key_ref(key);
71 return 0;
72}
73
74int dns_question_matches_rr(DnsQuestion *q, DnsResourceRecord *rr, const char *search_domain) {
75 size_t i;
76 int r;
77
78 assert(rr)do { if ((__builtin_expect(!!(!(rr)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("rr"), "../src/resolve/resolved-dns-question.c"
, 78, __PRETTY_FUNCTION__); } while (0)
;
79
80 if (!q)
81 return 0;
82
83 for (i = 0; i < q->n_keys; i++) {
84 r = dns_resource_key_match_rr(q->keys[i], rr, search_domain);
85 if (r != 0)
86 return r;
87 }
88
89 return 0;
90}
91
92int dns_question_matches_cname_or_dname(DnsQuestion *q, DnsResourceRecord *rr, const char *search_domain) {
93 size_t i;
94 int r;
95
96 assert(rr)do { if ((__builtin_expect(!!(!(rr)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("rr"), "../src/resolve/resolved-dns-question.c"
, 96, __PRETTY_FUNCTION__); } while (0)
;
97
98 if (!q)
99 return 0;
100
101 if (!IN_SET(rr->key->type, DNS_TYPE_CNAME, DNS_TYPE_DNAME)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){DNS_TYPE_CNAME, DNS_TYPE_DNAME})/sizeof(
int)]; switch(rr->key->type) { case DNS_TYPE_CNAME: case
DNS_TYPE_DNAME: _found = 1; break; default: break; } _found;
})
)
102 return 0;
103
104 for (i = 0; i < q->n_keys; i++) {
105 /* For a {C,D}NAME record we can never find a matching {C,D}NAME record */
106 if (!dns_type_may_redirect(q->keys[i]->type))
107 return 0;
108
109 r = dns_resource_key_match_cname_or_dname(q->keys[i], rr->key, search_domain);
110 if (r != 0)
111 return r;
112 }
113
114 return 0;
115}
116
117int dns_question_is_valid_for_query(DnsQuestion *q) {
118 const char *name;
119 size_t i;
120 int r;
121
122 if (!q)
123 return 0;
124
125 if (q->n_keys <= 0)
126 return 0;
127
128 if (q->n_keys > 65535)
129 return 0;
130
131 name = dns_resource_key_name(q->keys[0]);
132 if (!name)
133 return 0;
134
135 /* Check that all keys in this question bear the same name */
136 for (i = 0; i < q->n_keys; i++) {
137 assert(q->keys[i])do { if ((__builtin_expect(!!(!(q->keys[i])),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("q->keys[i]"), "../src/resolve/resolved-dns-question.c"
, 137, __PRETTY_FUNCTION__); } while (0)
;
138
139 if (i > 0) {
140 r = dns_name_equal(dns_resource_key_name(q->keys[i]), name);
141 if (r <= 0)
142 return r;
143 }
144
145 if (!dns_type_is_valid_query(q->keys[i]->type))
146 return 0;
147 }
148
149 return 1;
150}
151
152int dns_question_contains(DnsQuestion *a, const DnsResourceKey *k) {
153 size_t j;
154 int r;
155
156 assert(k)do { if ((__builtin_expect(!!(!(k)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("k"), "../src/resolve/resolved-dns-question.c"
, 156, __PRETTY_FUNCTION__); } while (0)
;
157
158 if (!a)
159 return 0;
160
161 for (j = 0; j < a->n_keys; j++) {
162 r = dns_resource_key_equal(a->keys[j], k);
163 if (r != 0)
164 return r;
165 }
166
167 return 0;
168}
169
170int dns_question_is_equal(DnsQuestion *a, DnsQuestion *b) {
171 size_t j;
172 int r;
173
174 if (a == b)
175 return 1;
176
177 if (!a)
178 return !b || b->n_keys == 0;
179 if (!b)
180 return a->n_keys == 0;
181
182 /* Checks if all keys in a are also contained b, and vice versa */
183
184 for (j = 0; j < a->n_keys; j++) {
185 r = dns_question_contains(b, a->keys[j]);
186 if (r <= 0)
187 return r;
188 }
189
190 for (j = 0; j < b->n_keys; j++) {
191 r = dns_question_contains(a, b->keys[j]);
192 if (r <= 0)
193 return r;
194 }
195
196 return 1;
197}
198
199int dns_question_cname_redirect(DnsQuestion *q, const DnsResourceRecord *cname, DnsQuestion **ret) {
200 _cleanup_(dns_question_unrefp)__attribute__((cleanup(dns_question_unrefp))) DnsQuestion *n = NULL((void*)0);
201 DnsResourceKey *key;
202 bool_Bool same = true1;
203 int r;
204
205 assert(cname)do { if ((__builtin_expect(!!(!(cname)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("cname"), "../src/resolve/resolved-dns-question.c"
, 205, __PRETTY_FUNCTION__); } while (0)
;
1
Assuming 'cname' is non-null
2
Taking false branch
3
Loop condition is false. Exiting loop
206 assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret"), "../src/resolve/resolved-dns-question.c"
, 206, __PRETTY_FUNCTION__); } while (0)
;
4
Assuming 'ret' is non-null
5
Taking false branch
6
Loop condition is false. Exiting loop
207 assert(IN_SET(cname->key->type, DNS_TYPE_CNAME, DNS_TYPE_DNAME))do { if ((__builtin_expect(!!(!(({ _Bool _found = 0; static __attribute__
((unused)) char _static_assert__macros_need_to_be_extended[20
- sizeof((int[]){DNS_TYPE_CNAME, DNS_TYPE_DNAME})/sizeof(int
)]; switch(cname->key->type) { case DNS_TYPE_CNAME: case
DNS_TYPE_DNAME: _found = 1; break; default: break; } _found;
}))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("IN_SET(cname->key->type, DNS_TYPE_CNAME, DNS_TYPE_DNAME)"
), "../src/resolve/resolved-dns-question.c", 207, __PRETTY_FUNCTION__
); } while (0)
;
7
Control jumps to 'case DNS_TYPE_CNAME:' at line 207
8
Execution continues on line 207
9
Taking false branch
10
Loop condition is false. Exiting loop
208
209 if (dns_question_size(q) <= 0) {
11
Assuming the condition is false
12
Taking false branch
210 *ret = NULL((void*)0);
211 return 0;
212 }
213
214 DNS_QUESTION_FOREACH(key, q)for (size_t __unique_prefix_i5 = ({ (key) = ((q) && (
q)->n_keys > 0) ? (q)->keys[0] : ((void*)0); 0; }); (
q) && (__unique_prefix_i5 < (q)->n_keys); __unique_prefix_i5
++, (key) = (__unique_prefix_i5 < (q)->n_keys ? (q)->
keys[__unique_prefix_i5] : ((void*)0)))
{
13
'?' condition is true
14
Loop condition is true. Entering loop body
215 _cleanup_free___attribute__((cleanup(freep))) char *destination = NULL((void*)0);
216 const char *d;
217
218 if (cname->key->type
14.1
Field 'type' is equal to DNS_TYPE_CNAME
== DNS_TYPE_CNAME)
15
Taking true branch
219 d = cname->cname.name;
220 else {
221 r = dns_name_change_suffix(dns_resource_key_name(key), dns_resource_key_name(cname->key), cname->dname.name, &destination);
222 if (r < 0)
223 return r;
224 if (r == 0)
225 continue;
226
227 d = destination;
228 }
229
230 r = dns_name_equal(dns_resource_key_name(key), d);
231 if (r < 0)
16
Assuming 'r' is >= 0
17
Taking false branch
232 return r;
233
234 if (r == 0) {
18
Assuming 'r' is equal to 0
19
Taking true branch
235 same = false0;
236 break;
20
Execution continues on line 241
237 }
238 }
239
240 /* Fully the same, indicate we didn't do a thing */
241 if (same
20.1
'same' is false
) {
21
Taking false branch
242 *ret = NULL((void*)0);
243 return 0;
244 }
245
246 n = dns_question_new(q->n_keys);
22
Calling 'dns_question_new'
28
Returned allocated memory
247 if (!n
28.1
'n' is non-null
)
29
Taking false branch
248 return -ENOMEM12;
249
250 /* Create a new question, and patch in the new name */
251 DNS_QUESTION_FOREACH(key, q)for (size_t __unique_prefix_i6 = ({ (key) = ((q) && (
q)->n_keys > 0) ? (q)->keys[0] : ((void*)0); 0; }); (
q) && (__unique_prefix_i6 < (q)->n_keys); __unique_prefix_i6
++, (key) = (__unique_prefix_i6 < (q)->n_keys ? (q)->
keys[__unique_prefix_i6] : ((void*)0)))
{
30
'?' condition is true
31
Loop condition is true. Entering loop body
252 _cleanup_(dns_resource_key_unrefp)__attribute__((cleanup(dns_resource_key_unrefp))) DnsResourceKey *k = NULL((void*)0);
253
254 k = dns_resource_key_new_redirect(key, cname);
255 if (!k)
32
Assuming 'k' is null
33
Taking true branch
256 return -ENOMEM12;
34
Potential leak of memory pointed to by 'n'
257
258 r = dns_question_add(n, k);
259 if (r < 0)
260 return r;
261 }
262
263 *ret = TAKE_PTR(n)({ typeof(n) _ptr_ = (n); (n) = ((void*)0); _ptr_; });
264
265 return 1;
266}
267
268const char *dns_question_first_name(DnsQuestion *q) {
269
270 if (!q)
271 return NULL((void*)0);
272
273 if (q->n_keys < 1)
274 return NULL((void*)0);
275
276 return dns_resource_key_name(q->keys[0]);
277}
278
279int dns_question_new_address(DnsQuestion **ret, int family, const char *name, bool_Bool convert_idna) {
280 _cleanup_(dns_question_unrefp)__attribute__((cleanup(dns_question_unrefp))) DnsQuestion *q = NULL((void*)0);
281 _cleanup_free___attribute__((cleanup(freep))) char *buf = NULL((void*)0);
282 int r;
283
284 assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret"), "../src/resolve/resolved-dns-question.c"
, 284, __PRETTY_FUNCTION__); } while (0)
;
285 assert(name)do { if ((__builtin_expect(!!(!(name)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("name"), "../src/resolve/resolved-dns-question.c"
, 285, __PRETTY_FUNCTION__); } while (0)
;
286
287 if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){2, 10, 0})/sizeof(int)]; switch(family) {
case 2: case 10: case 0: _found = 1; break; default: break; }
_found; })
)
288 return -EAFNOSUPPORT97;
289
290 if (convert_idna) {
291 r = dns_name_apply_idna(name, &buf);
292 if (r < 0)
293 return r;
294 if (r > 0 && !streq(name, buf)(strcmp((name),(buf)) == 0))
295 name = buf;
296 else
297 /* We did not manage to create convert the idna name, or it's
298 * the same as the original name. We assume the caller already
299 * created an uncoverted question, so let's not repeat work
300 * unnecessarily. */
301 return -EALREADY114;
302 }
303
304 q = dns_question_new(family == AF_UNSPEC0 ? 2 : 1);
305 if (!q)
306 return -ENOMEM12;
307
308 if (family != AF_INET610) {
309 _cleanup_(dns_resource_key_unrefp)__attribute__((cleanup(dns_resource_key_unrefp))) DnsResourceKey *key = NULL((void*)0);
310
311 key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, name);
312 if (!key)
313 return -ENOMEM12;
314
315 r = dns_question_add(q, key);
316 if (r < 0)
317 return r;
318 }
319
320 if (family != AF_INET2) {
321 _cleanup_(dns_resource_key_unrefp)__attribute__((cleanup(dns_resource_key_unrefp))) DnsResourceKey *key = NULL((void*)0);
322
323 key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_AAAA, name);
324 if (!key)
325 return -ENOMEM12;
326
327 r = dns_question_add(q, key);
328 if (r < 0)
329 return r;
330 }
331
332 *ret = TAKE_PTR(q)({ typeof(q) _ptr_ = (q); (q) = ((void*)0); _ptr_; });
333
334 return 0;
335}
336
337int dns_question_new_reverse(DnsQuestion **ret, int family, const union in_addr_union *a) {
338 _cleanup_(dns_resource_key_unrefp)__attribute__((cleanup(dns_resource_key_unrefp))) DnsResourceKey *key = NULL((void*)0);
339 _cleanup_(dns_question_unrefp)__attribute__((cleanup(dns_question_unrefp))) DnsQuestion *q = NULL((void*)0);
340 _cleanup_free___attribute__((cleanup(freep))) char *reverse = NULL((void*)0);
341 int r;
342
343 assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret"), "../src/resolve/resolved-dns-question.c"
, 343, __PRETTY_FUNCTION__); } while (0)
;
344 assert(a)do { if ((__builtin_expect(!!(!(a)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("a"), "../src/resolve/resolved-dns-question.c"
, 344, __PRETTY_FUNCTION__); } while (0)
;
345
346 if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){2, 10, 0})/sizeof(int)]; switch(family) {
case 2: case 10: case 0: _found = 1; break; default: break; }
_found; })
)
347 return -EAFNOSUPPORT97;
348
349 r = dns_name_reverse(family, a, &reverse);
350 if (r < 0)
351 return r;
352
353 q = dns_question_new(1);
354 if (!q)
355 return -ENOMEM12;
356
357 key = dns_resource_key_new_consume(DNS_CLASS_IN, DNS_TYPE_PTR, reverse);
358 if (!key)
359 return -ENOMEM12;
360
361 reverse = NULL((void*)0);
362
363 r = dns_question_add(q, key);
364 if (r < 0)
365 return r;
366
367 *ret = TAKE_PTR(q)({ typeof(q) _ptr_ = (q); (q) = ((void*)0); _ptr_; });
368
369 return 0;
370}
371
372int dns_question_new_service(
373 DnsQuestion **ret,
374 const char *service,
375 const char *type,
376 const char *domain,
377 bool_Bool with_txt,
378 bool_Bool convert_idna) {
379
380 _cleanup_(dns_resource_key_unrefp)__attribute__((cleanup(dns_resource_key_unrefp))) DnsResourceKey *key = NULL((void*)0);
381 _cleanup_(dns_question_unrefp)__attribute__((cleanup(dns_question_unrefp))) DnsQuestion *q = NULL((void*)0);
382 _cleanup_free___attribute__((cleanup(freep))) char *buf = NULL((void*)0), *joined = NULL((void*)0);
383 const char *name;
384 int r;
385
386 assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret"), "../src/resolve/resolved-dns-question.c"
, 386, __PRETTY_FUNCTION__); } while (0)
;
387
388 /* We support three modes of invocation:
389 *
390 * 1. Only a domain is specified, in which case we assume a properly encoded SRV RR name, including service
391 * type and possibly a service name. If specified in this way we assume it's already IDNA converted if
392 * that's necessary.
393 *
394 * 2. Both service type and a domain specified, in which case a normal SRV RR is assumed, without a DNS-SD
395 * style prefix. In this case we'll IDNA convert the domain, if that's requested.
396 *
397 * 3. All three of service name, type and domain are specified, in which case a DNS-SD service is put
398 * together. The service name is never IDNA converted, and the domain is if requested.
399 *
400 * It's not supported to specify a service name without a type, or no domain name.
401 */
402
403 if (!domain)
404 return -EINVAL22;
405
406 if (type) {
407 if (convert_idna) {
408 r = dns_name_apply_idna(domain, &buf);
409 if (r < 0)
410 return r;
411 if (r > 0)
412 domain = buf;
413 }
414
415 r = dns_service_join(service, type, domain, &joined);
416 if (r < 0)
417 return r;
418
419 name = joined;
420 } else {
421 if (service)
422 return -EINVAL22;
423
424 name = domain;
425 }
426
427 q = dns_question_new(1 + with_txt);
428 if (!q)
429 return -ENOMEM12;
430
431 key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_SRV, name);
432 if (!key)
433 return -ENOMEM12;
434
435 r = dns_question_add(q, key);
436 if (r < 0)
437 return r;
438
439 if (with_txt) {
440 dns_resource_key_unref(key);
441 key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_TXT, name);
442 if (!key)
443 return -ENOMEM12;
444
445 r = dns_question_add(q, key);
446 if (r < 0)
447 return r;
448 }
449
450 *ret = TAKE_PTR(q)({ typeof(q) _ptr_ = (q); (q) = ((void*)0); _ptr_; });
451
452 return 0;
453}