From 06b5c95b058e4985a844a72bfc98ab0dd157a364 Mon Sep 17 00:00:00 2001 From: Petr Menšík Date: Sep 09 2021 07:55:19 +0000 Subject: Add coverity patches Various coverity fixes, not yet sent to upstream. --- diff --git a/0001-Retry-on-interrupted-error-in-tftp.patch b/0001-Retry-on-interrupted-error-in-tftp.patch new file mode 100644 index 0000000..f486f2d --- /dev/null +++ b/0001-Retry-on-interrupted-error-in-tftp.patch @@ -0,0 +1,35 @@ +From f5f56c001dddd486859dc6301e6cbe00ba604fe8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= +Date: Wed, 18 Aug 2021 10:09:35 +0200 +Subject: [PATCH 01/15] Retry on interrupted error in tftp + +Interrupt might arrive when sending error reply. Retry if possible. + +Wrong Check of Return Value + +10. dnsmasq-2.85/src/tftp.c:603: check_return: Calling "sendto(transfer->sockfd, dnsmasq_daemon->packet, len, 0, __CONST_SOCKADDR_ARG({.__sockaddr__ = &peer.sa}), sa_len(&peer))" without checking return value. This library function may fail and return an error code. + # 601| prettyprint_addr(&peer, daemon->addrbuff); + # 602| len = tftp_err(ERR_TID, daemon->packet, _("ignoring packet from %s (TID mismatch)"), daemon->addrbuff); + # 603|-> sendto(transfer->sockfd, daemon->packet, len, 0, &peer.sa, sa_len(&peer)); + # 604| } + # 605| } +--- + src/tftp.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/tftp.c b/src/tftp.c +index 37bdff2..3d87523 100644 +--- a/src/tftp.c ++++ b/src/tftp.c +@@ -600,7 +600,7 @@ void check_tftp_listeners(time_t now) + /* Wrong source address. See rfc1350 para 4. */ + prettyprint_addr(&peer, daemon->addrbuff); + len = tftp_err(ERR_TID, daemon->packet, _("ignoring packet from %s (TID mismatch)"), daemon->addrbuff); +- sendto(transfer->sockfd, daemon->packet, len, 0, &peer.sa, sa_len(&peer)); ++ while(retry_send(sendto(transfer->sockfd, daemon->packet, len, 0, &peer.sa, sa_len(&peer)))); + } + } + } +-- +2.31.1 + diff --git a/0002-Add-safety-checks-to-places-pointed-by-Coverity.patch b/0002-Add-safety-checks-to-places-pointed-by-Coverity.patch new file mode 100644 index 0000000..8fc70a5 --- /dev/null +++ b/0002-Add-safety-checks-to-places-pointed-by-Coverity.patch @@ -0,0 +1,77 @@ +From 061013293ceddce509ae06a31a045e803103f1ce Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= +Date: Wed, 18 Aug 2021 14:59:23 +0200 +Subject: [PATCH 02/15] Add safety checks to places pointed by Coverity + +GCC Analyzer (experimental) + +1. dnsmasq-2.85/src/forward.c:0: scope_hint: In function 'allocate_rfd.part.0' +2. dnsmasq-2.85/src/forward.c:2321:18: warning[-Wanalyzer-null-dereference]: dereference of NULL 'rfd' + # 2319| *fdlp = rfl; + # 2320| + # 2321|-> return rfl->rfd->fd; + # 2322| } + # 2323| + +1. dnsmasq-2.85/src/cache.c:0: scope_hint: In function 'log_query' +2. dnsmasq-2.85/src/cache.c:1969:20: warning[-Wanalyzer-null-dereference]: dereference of NULL 'name' + # 1967| source = "cached"; + # 1968| + # 1969|-> if (strlen(name) == 0) + # 1970| name = "."; + # 1971| + +1. dnsmasq-2.85/src/cache.c:0: scope_hint: In function 'cache_scan_free' +2. dnsmasq-2.85/src/cache.c:436:20: warning[-Wanalyzer-null-argument]: use of NULL 'addr' where non-null expected +40. /usr/include/sys/un.h:37: included_from: Included from here. +41. dnsmasq-2.85/src/dnsmasq.h:101: included_from: Included from here. +42. dnsmasq-2.85/src/cache.c:17: included_from: Included from here. +43. /usr/include/string.h:64:12: note: argument 2 of 'memcmp' must be non-null + # 434| (flags & crecp->flags & F_REVERSE) && + # 435| (flags & crecp->flags & (F_IPV4 | F_IPV6)) && + # 436|-> memcmp(&crecp->addr, addr, addrlen) == 0) + # 437| { + # 438| *up = crecp->hash_next; +--- + src/cache.c | 4 ++-- + src/forward.c | 2 +- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/cache.c b/src/cache.c +index 8add610..97c51a7 100644 +--- a/src/cache.c ++++ b/src/cache.c +@@ -433,7 +433,7 @@ static struct crec *cache_scan_free(char *name, union all_addr *addr, unsigned s + else if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) && + (flags & crecp->flags & F_REVERSE) && + (flags & crecp->flags & (F_IPV4 | F_IPV6)) && +- memcmp(&crecp->addr, addr, addrlen) == 0) ++ addr && memcmp(&crecp->addr, addr, addrlen) == 0) + { + *up = crecp->hash_next; + cache_unlink(crecp); +@@ -2013,7 +2013,7 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg) + else + source = "cached"; + +- if (strlen(name) == 0) ++ if (name && !name[0]) + name = "."; + + if (option_bool(OPT_EXTRALOG)) +diff --git a/src/forward.c b/src/forward.c +index 3d638e4..f07c908 100644 +--- a/src/forward.c ++++ b/src/forward.c +@@ -2276,7 +2276,7 @@ int allocate_rfd(struct randfd_list **fdlp, struct server *serv) + } + } + +- if (j == daemon->numrrand) ++ if (!rfd) /* should be when j == daemon->numrrand */ + { + struct randfd_list *rfl_poll; + +-- +2.31.1 + diff --git a/0003-Small-safeguard-to-unexpected-data.patch b/0003-Small-safeguard-to-unexpected-data.patch new file mode 100644 index 0000000..c496640 --- /dev/null +++ b/0003-Small-safeguard-to-unexpected-data.patch @@ -0,0 +1,28 @@ +From 920cd815bafea084f68cc4309399aea77bd7f66b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= +Date: Fri, 3 Sep 2021 14:11:42 +0200 +Subject: [PATCH 03/15] Small safeguard to unexpected data + +Make sure negative index is not used for comparison. It seems code in +option parsing does not allow it to be empty, but insist on it also in +this place. +--- + src/dhcp-common.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/dhcp-common.c b/src/dhcp-common.c +index 73568a9..85b269a 100644 +--- a/src/dhcp-common.c ++++ b/src/dhcp-common.c +@@ -88,7 +88,7 @@ int match_netid_wild(struct dhcp_netid *check, struct dhcp_netid *pool) + for (; check; check = check->next) + { + const int check_len = strlen(check->net); +- const int is_wc = (check->net[check_len - 1] == '*'); ++ const int is_wc = (check_len > 0 && check->net[check_len - 1] == '*'); + + /* '#' for not is for backwards compat. */ + if (check->net[0] != '!' && check->net[0] != '#') +-- +2.31.1 + diff --git a/0004-Fix-bunch-of-warnings-in-auth.c.patch b/0004-Fix-bunch-of-warnings-in-auth.c.patch new file mode 100644 index 0000000..976255f --- /dev/null +++ b/0004-Fix-bunch-of-warnings-in-auth.c.patch @@ -0,0 +1,153 @@ +From e61af561900b4d2dd976a575b2efd388be092742 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= +Date: Fri, 3 Sep 2021 16:00:35 +0200 +Subject: [PATCH 04/15] Fix bunch of warnings in auth.c + +Error: CLANG_WARNING: [#def7] +dnsmasq-2.86test7/src/auth.c:420:5: warning[deadcode.DeadStores]: Value stored to 'found' is never read + # 418| if (!found && is_name_synthetic(flag, name, &addr) ) + # 419| { + # 420|-> found = 1; + # 421| nxdomain = 0; + # 422| + +Error: CLANG_WARNING: [#def8] +dnsmasq-2.86test7/src/auth.c:436:8: warning[deadcode.DeadStores]: Value stored to 'found' is never read + # 434| { + # 435| auth = soa = 1; /* inhibits auth section */ + # 436|-> found = 1; + # 437| log_query(F_RRNAME | F_AUTH, zone->domain, NULL, ""); + # 438| } + +Error: CLANG_WARNING: [#def9] +dnsmasq-2.86test7/src/auth.c:472:8: warning[deadcode.DeadStores]: Value stored to 'found' is never read + # 470| ns = 1; /* ensure we include NS records! */ + # 471| axfr = 1; + # 472|-> found = 1; + # 473| axfroffset = nameoffset; + # 474| log_query(F_RRNAME | F_AUTH, zone->domain, NULL, ""); + +Error: CLANG_WARNING: [#def10] +dnsmasq-2.86test7/src/auth.c:480:8: warning[deadcode.DeadStores]: Value stored to 'found' is never read + # 478| auth = 1; + # 479| ns = 1; /* inhibits auth section */ + # 480|-> found = 1; + # 481| log_query(F_RRNAME | F_AUTH, zone->domain, NULL, ""); + # 482| } + +Error: CLANG_WARNING: [#def11] +dnsmasq-2.86test7/src/auth.c:501:4: warning[deadcode.DeadStores]: Value stored to 'found' is never read + # 499| log_query(crecp->flags, name, &crecp->addr, record_source(crecp->uid)); + # 500| *cut = 0; /* remove domain part */ + # 501|-> found = 1; + # 502| if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, + # 503| daemon->auth_ttl, NULL, qtype, C_IN, + +Error: CLANG_WARNING: [#def12] +dnsmasq-2.86test7/src/auth.c:522:8: warning[deadcode.DeadStores]: Value stored to 'found' is never read + # 520| { + # 521| log_query(crecp->flags, name, &crecp->addr, record_source(crecp->uid)); + # 522|-> found = 1; + # 523| if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, + # 524| daemon->auth_ttl, NULL, qtype, C_IN, + +Error: CLANG_WARNING: [#def13] +dnsmasq-2.86test7/src/auth.c:617:8: warning[deadcode.DeadStores]: Value stored to 'p' is never read + # 615| p += sprintf(p, "%u.", a & 0xff); + # 616| a = a >> 8; + # 617|-> p += sprintf(p, "%u.in-addr.arpa", a & 0xff); + # 618| + # 619| } + +Error: CPPCHECK_WARNING (CWE-758): [#def14] +dnsmasq-2.86test7/src/auth.c:627: warning[objectIndex]: The address of local variable 'addr6' might be accessed at non-zero index. + # 625| for (i = subnet->prefixlen-1; i >= 0; i -= 4) + # 626| { + # 627|-> int dig = ((unsigned char *)&subnet->addr.addr6)[i>>3]; + # 628| p += sprintf(p, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4); + # 629| } + +Error: CLANG_WARNING: [#def15] +dnsmasq-2.86test7/src/auth.c:630:8: warning[deadcode.DeadStores]: Value stored to 'p' is never read + # 628| p += sprintf(p, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4); + # 629| } + # 630|-> p += sprintf(p, "ip6.arpa"); + # 631| + # 632| } +--- + src/auth.c | 10 ++-------- + 1 file changed, 2 insertions(+), 8 deletions(-) + +diff --git a/src/auth.c b/src/auth.c +index 172a4b2..4f03c39 100644 +--- a/src/auth.c ++++ b/src/auth.c +@@ -417,7 +417,6 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n + + if (!found && is_name_synthetic(flag, name, &addr) ) + { +- found = 1; + nxdomain = 0; + + log_query(F_FORWARD | F_CONFIG | flag, name, &addr, NULL); +@@ -433,7 +432,6 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n + if (qtype == T_SOA) + { + auth = soa = 1; /* inhibits auth section */ +- found = 1; + log_query(F_RRNAME | F_AUTH, zone->domain, NULL, ""); + } + else if (qtype == T_AXFR) +@@ -469,7 +467,6 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n + soa = 1; /* inhibits auth section */ + ns = 1; /* ensure we include NS records! */ + axfr = 1; +- found = 1; + axfroffset = nameoffset; + log_query(F_RRNAME | F_AUTH, zone->domain, NULL, ""); + } +@@ -477,7 +474,6 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n + { + auth = 1; + ns = 1; /* inhibits auth section */ +- found = 1; + log_query(F_RRNAME | F_AUTH, zone->domain, NULL, ""); + } + } +@@ -498,7 +494,6 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n + *cut = '.'; /* restore domain part */ + log_query(crecp->flags, name, &crecp->addr, record_source(crecp->uid)); + *cut = 0; /* remove domain part */ +- found = 1; + if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, + daemon->auth_ttl, NULL, qtype, C_IN, + qtype == T_A ? "4" : "6", &crecp->addr)) +@@ -519,7 +514,6 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n + if ((crecp->flags & flag) && (local_query || filter_zone(zone, flag, &(crecp->addr)))) + { + log_query(crecp->flags, name, &crecp->addr, record_source(crecp->uid)); +- found = 1; + if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, + daemon->auth_ttl, NULL, qtype, C_IN, + qtype == T_A ? "4" : "6", &crecp->addr)) +@@ -614,7 +608,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n + if (subnet->prefixlen >= 16 ) + p += sprintf(p, "%u.", a & 0xff); + a = a >> 8; +- p += sprintf(p, "%u.in-addr.arpa", a & 0xff); ++ sprintf(p, "%u.in-addr.arpa", a & 0xff); + + } + else +@@ -627,7 +621,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n + int dig = ((unsigned char *)&subnet->addr.addr6)[i>>3]; + p += sprintf(p, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4); + } +- p += sprintf(p, "ip6.arpa"); ++ sprintf(p, "ip6.arpa"); + + } + } +-- +2.31.1 + diff --git a/0005-Fix-few-coverity-warnings-in-lease-tools.patch b/0005-Fix-few-coverity-warnings-in-lease-tools.patch new file mode 100644 index 0000000..ab24440 --- /dev/null +++ b/0005-Fix-few-coverity-warnings-in-lease-tools.patch @@ -0,0 +1,148 @@ +From be7f213066282baeed46cc34223601c462db9cbf Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= +Date: Fri, 3 Sep 2021 16:32:05 +0200 +Subject: [PATCH 05/15] Fix few coverity warnings in lease-tools + +Error: UNINIT (CWE-457): [#def2] +dnsmasq-2.86test7/contrib/lease-tools/dhcp_release.c:265: var_decl: Declaring variable "ifr" without initializer. +dnsmasq-2.86test7/contrib/lease-tools/dhcp_release.c:285: uninit_use_in_call: Using uninitialized value "ifr". Field "ifr.ifr_ifru" is uninitialized when calling "setsockopt". + # 283| strncpy(ifr.ifr_name, argv[1], sizeof(ifr.ifr_name)-1); + # 284| ifr.ifr_name[sizeof(ifr.ifr_name)-1] = '\0'; + # 285|-> if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) == -1) + # 286| { + # 287| perror("cannot setup interface"); + +Error: CHECKED_RETURN (CWE-252): [#def3] +dnsmasq-2.86test7/contrib/lease-tools/dhcp_release6.c:346: check_return: Calling "inet_pton" without checking return value (as is done elsewhere 61 out of 72 times). +dnsmasq-2.86test7/contrib/lease-tools/dhcp_release6.c:188: example_assign: Example 1: Assigning: "s" = return value from "inet_pton(10, ip, &result.ip)". +dnsmasq-2.86test7/contrib/lease-tools/dhcp_release6.c:189: example_checked: Example 1 (cont.): "s" has its value checked in "s <= 0". +dnsmasq-2.86test7/src/cache.c:1108: example_checked: Example 2: "inet_pton(10, token, &addr)" has its value checked in "inet_pton(10, token, &addr) > 0". +dnsmasq-2.86test7/src/dbus.c:525: example_checked: Example 3: "inet_pton(2, ipaddr, &addr.addr4)" has its value checked in "inet_pton(2, ipaddr, &addr.addr4)". +dnsmasq-2.86test7/src/domain.c:138: example_checked: Example 4: "inet_pton(prot, tail, addr)" has its value checked in "inet_pton(prot, tail, addr)". +dnsmasq-2.86test7/src/lease.c:81: example_checked: Example 5: "inet_pton(10, dnsmasq_daemon->namebuff, &addr.addr6)" has its value checked in "inet_pton(10, dnsmasq_daemon->namebuff, &addr.addr6)". + # 344| client_addr.sin6_flowinfo = 0; + # 345| client_addr.sin6_scope_id =0; + # 346|-> inet_pton(AF_INET6, "::", &client_addr.sin6_addr); + # 347| bind(sock, (struct sockaddr*)&client_addr, sizeof(struct sockaddr_in6)); + # 348| inet_pton(AF_INET6, DHCP6_MULTICAST_ADDRESS, &server_addr.sin6_addr); + +Error: CHECKED_RETURN (CWE-252): [#def4] +dnsmasq-2.86test7/contrib/lease-tools/dhcp_release6.c:347: check_return: Calling "bind(sock, (struct sockaddr *)&client_addr, 28U)" without checking return value. This library function may fail and return an error code. + # 345| client_addr.sin6_scope_id =0; + # 346| inet_pton(AF_INET6, "::", &client_addr.sin6_addr); + # 347|-> bind(sock, (struct sockaddr*)&client_addr, sizeof(struct sockaddr_in6)); + # 348| inet_pton(AF_INET6, DHCP6_MULTICAST_ADDRESS, &server_addr.sin6_addr); + # 349| server_addr.sin6_port = htons(DHCP6_SERVER_PORT); + +Error: CHECKED_RETURN (CWE-252): [#def5] +dnsmasq-2.86test7/contrib/lease-tools/dhcp_release6.c:348: check_return: Calling "inet_pton" without checking return value (as is done elsewhere 61 out of 72 times). +dnsmasq-2.86test7/contrib/lease-tools/dhcp_release6.c:188: example_assign: Example 1: Assigning: "s" = return value from "inet_pton(10, ip, &result.ip)". +dnsmasq-2.86test7/contrib/lease-tools/dhcp_release6.c:189: example_checked: Example 1 (cont.): "s" has its value checked in "s <= 0". +dnsmasq-2.86test7/src/cache.c:1108: example_checked: Example 2: "inet_pton(10, token, &addr)" has its value checked in "inet_pton(10, token, &addr) > 0". +dnsmasq-2.86test7/src/dbus.c:525: example_checked: Example 3: "inet_pton(2, ipaddr, &addr.addr4)" has its value checked in "inet_pton(2, ipaddr, &addr.addr4)". +dnsmasq-2.86test7/src/domain.c:138: example_checked: Example 4: "inet_pton(prot, tail, addr)" has its value checked in "inet_pton(prot, tail, addr)". +dnsmasq-2.86test7/src/lease.c:81: example_checked: Example 5: "inet_pton(10, dnsmasq_daemon->namebuff, &addr.addr6)" has its value checked in "inet_pton(10, dnsmasq_daemon->namebuff, &addr.addr6)". + # 346| inet_pton(AF_INET6, "::", &client_addr.sin6_addr); + # 347| bind(sock, (struct sockaddr*)&client_addr, sizeof(struct sockaddr_in6)); + # 348|-> inet_pton(AF_INET6, DHCP6_MULTICAST_ADDRESS, &server_addr.sin6_addr); + # 349| server_addr.sin6_port = htons(DHCP6_SERVER_PORT); + # 350| int16_t recv_size = 0; + +Error: NEGATIVE_RETURNS (CWE-394): [#def6] +dnsmasq-2.86test7/contrib/lease-tools/dhcp_release6.c:360: var_tested_neg: Variable "recv_size" tests negative. +dnsmasq-2.86test7/contrib/lease-tools/dhcp_release6.c:373: negative_returns: "recv_size" is passed to a parameter that cannot be negative. + # 371| } + # 372| + # 373|-> int16_t result = parse_packet(response, recv_size); + # 374| if (result == NOT_REPLY_CODE) + # 375| { +--- + contrib/lease-tools/dhcp_release.c | 1 + + contrib/lease-tools/dhcp_release6.c | 37 ++++++++++++++++++----------- + 2 files changed, 24 insertions(+), 14 deletions(-) + +diff --git a/contrib/lease-tools/dhcp_release.c b/contrib/lease-tools/dhcp_release.c +index c1c835b..84f5610 100644 +--- a/contrib/lease-tools/dhcp_release.c ++++ b/contrib/lease-tools/dhcp_release.c +@@ -280,6 +280,7 @@ int main(int argc, char **argv) + + /* This voodoo fakes up a packet coming from the correct interface, which really matters for + a DHCP server */ ++ memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, argv[1], sizeof(ifr.ifr_name)-1); + ifr.ifr_name[sizeof(ifr.ifr_name)-1] = '\0'; + if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) == -1) +diff --git a/contrib/lease-tools/dhcp_release6.c b/contrib/lease-tools/dhcp_release6.c +index d680222..9b3438f 100644 +--- a/contrib/lease-tools/dhcp_release6.c ++++ b/contrib/lease-tools/dhcp_release6.c +@@ -318,6 +318,12 @@ void usage(const char* arg, FILE* stream) + fprintf (stream, "Usage: %s %s\n", arg, usage_string); + } + ++static void fail_fatal(const char *errstr, int exitcode) ++{ ++ perror(errstr); ++ exit(exitcode); ++} ++ + int send_release_packet(const char* iface, struct dhcp6_packet* packet) + { + struct sockaddr_in6 server_addr, client_addr; +@@ -343,18 +349,19 @@ int send_release_packet(const char* iface, struct dhcp6_packet* packet) + client_addr.sin6_port = htons(DHCP6_CLIENT_PORT); + client_addr.sin6_flowinfo = 0; + client_addr.sin6_scope_id =0; +- inet_pton(AF_INET6, "::", &client_addr.sin6_addr); +- bind(sock, (struct sockaddr*)&client_addr, sizeof(struct sockaddr_in6)); +- inet_pton(AF_INET6, DHCP6_MULTICAST_ADDRESS, &server_addr.sin6_addr); ++ if (inet_pton(AF_INET6, "::", &client_addr.sin6_addr) <= 0) ++ fail_fatal("inet_pton", 5); ++ if (bind(sock, (struct sockaddr*)&client_addr, sizeof(struct sockaddr_in6)) != 0) ++ perror("bind"); /* continue on bind error */ ++ if (inet_pton(AF_INET6, DHCP6_MULTICAST_ADDRESS, &server_addr.sin6_addr) <= 0) ++ fail_fatal("inet_pton", 5); + server_addr.sin6_port = htons(DHCP6_SERVER_PORT); +- int16_t recv_size = 0; ++ ssize_t recv_size = 0; ++ int result; + for (i = 0; i < 5; i++) + { + if (sendto(sock, packet->buf, packet->len, 0, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) +- { +- perror("sendto failed"); +- exit(4); +- } ++ fail_fatal("sendto failed", 4); + + recv_size = recvfrom(sock, response, sizeof(response), MSG_DONTWAIT, NULL, 0); + if (recv_size == -1) +@@ -367,16 +374,18 @@ int send_release_packet(const char* iface, struct dhcp6_packet* packet) + else + { + perror("recvfrom"); ++ result = UNSPEC_FAIL; + } + } +- +- int16_t result = parse_packet(response, recv_size); +- if (result == NOT_REPLY_CODE) ++ else + { +- sleep(1); +- continue; ++ result = parse_packet(response, recv_size); ++ if (result == NOT_REPLY_CODE) ++ { ++ sleep(1); ++ continue; ++ } + } +- + close(sock); + return result; + } +-- +2.31.1 + diff --git a/0006-Fix-coverity-formats-issues-in-blockdata.patch b/0006-Fix-coverity-formats-issues-in-blockdata.patch new file mode 100644 index 0000000..beb0898 --- /dev/null +++ b/0006-Fix-coverity-formats-issues-in-blockdata.patch @@ -0,0 +1,48 @@ +From 3a077065ce846e301b532127ebecdd2771ad75ed Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= +Date: Fri, 3 Sep 2021 16:41:00 +0200 +Subject: [PATCH 06/15] Fix coverity formats issues in blockdata + +Error: PRINTF_ARGS (CWE-686): [#def16] +dnsmasq-2.86test7/src/blockdata.c:56: invalid_type: Argument "blockdata_count * 48UL" to format specifier "%u" was expected to have type "unsigned int" but has type "unsigned long". + # 54| { + # 55| my_syslog(LOG_INFO, _("pool memory in use %u, max %u, allocated %u"), + # 56|-> blockdata_count * sizeof(struct blockdata), + # 57| blockdata_hwm * sizeof(struct blockdata), + # 58| blockdata_alloced * sizeof(struct blockdata)); + +Error: PRINTF_ARGS (CWE-686): [#def17] +dnsmasq-2.86test7/src/blockdata.c:57: invalid_type: Argument "blockdata_hwm * 48UL" to format specifier "%u" was expected to have type "unsigned int" but has type "unsigned long". + # 55| my_syslog(LOG_INFO, _("pool memory in use %u, max %u, allocated %u"), + # 56| blockdata_count * sizeof(struct blockdata), + # 57|-> blockdata_hwm * sizeof(struct blockdata), + # 58| blockdata_alloced * sizeof(struct blockdata)); + # 59| } + +Error: PRINTF_ARGS (CWE-686): [#def18] +dnsmasq-2.86test7/src/blockdata.c:58: invalid_type: Argument "blockdata_alloced * 48UL" to format specifier "%u" was expected to have type "unsigned int" but has type "unsigned long". + # 56| blockdata_count * sizeof(struct blockdata), + # 57| blockdata_hwm * sizeof(struct blockdata), + # 58|-> blockdata_alloced * sizeof(struct blockdata)); + # 59| } + # 60| +--- + src/blockdata.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/blockdata.c b/src/blockdata.c +index f7740b5..0986285 100644 +--- a/src/blockdata.c ++++ b/src/blockdata.c +@@ -52,7 +52,7 @@ void blockdata_init(void) + + void blockdata_report(void) + { +- my_syslog(LOG_INFO, _("pool memory in use %u, max %u, allocated %u"), ++ my_syslog(LOG_INFO, _("pool memory in use %zu, max %zu, allocated %zu"), + blockdata_count * sizeof(struct blockdata), + blockdata_hwm * sizeof(struct blockdata), + blockdata_alloced * sizeof(struct blockdata)); +-- +2.31.1 + diff --git a/0007-Retry-dhcp6-ping-on-interrupts.patch b/0007-Retry-dhcp6-ping-on-interrupts.patch new file mode 100644 index 0000000..1beb806 --- /dev/null +++ b/0007-Retry-dhcp6-ping-on-interrupts.patch @@ -0,0 +1,32 @@ +From 467b621fb7da6e1318ac7204325b0adb01b3ff19 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= +Date: Fri, 3 Sep 2021 16:48:50 +0200 +Subject: [PATCH 07/15] Retry dhcp6 ping on interrupts + +Error: CHECKED_RETURN (CWE-252): [#def35] +dnsmasq-2.86test7/src/dhcp6.c:295: check_return: Calling "sendto(dnsmasq_daemon->icmp6fd, &neigh, 24UL, 0, __CONST_SOCKADDR_ARG({.__sockaddr__ = &addr.sa}), 28U)" without checking return value. This library function may fail and return an error code. + # 293| break; + # 294| + # 295|-> sendto(daemon->icmp6fd, &neigh, sizeof(neigh), 0, &addr.sa, sizeof(addr)); + # 296| + # 297| ts.tv_sec = 0; +--- + src/dhcp6.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/dhcp6.c b/src/dhcp6.c +index 2be877f..ae1f5c1 100644 +--- a/src/dhcp6.c ++++ b/src/dhcp6.c +@@ -292,7 +292,7 @@ void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac, unsi + if ((maclen = find_mac(&addr, mac, 0, now)) != 0) + break; + +- sendto(daemon->icmp6fd, &neigh, sizeof(neigh), 0, &addr.sa, sizeof(addr)); ++ while(retry_send(sendto(daemon->icmp6fd, &neigh, sizeof(neigh), 0, &addr.sa, sizeof(addr)))); + + ts.tv_sec = 0; + ts.tv_nsec = 100000000; /* 100ms */ +-- +2.31.1 + diff --git a/0008-Fix-coverity-warnings-on-dbus.patch b/0008-Fix-coverity-warnings-on-dbus.patch new file mode 100644 index 0000000..fd02da5 --- /dev/null +++ b/0008-Fix-coverity-warnings-on-dbus.patch @@ -0,0 +1,131 @@ +From bbfdf6a435cbd5f71ae76f962ce86786346589aa Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= +Date: Fri, 3 Sep 2021 17:19:05 +0200 +Subject: [PATCH 08/15] Fix coverity warnings on dbus + +Error: CLANG_WARNING: [#def30] +dnsmasq-2.86test7/src/dbus.c:117:3: warning[deadcode.DeadStores]: Value stored to 'w' is never read + # 115| daemon->watches = w; + # 116| + # 117|-> w = data; /* no warning */ + # 118| return TRUE; + # 119| } + +Error: CLANG_WARNING: [#def31] +dnsmasq-2.86test7/src/dbus.c:137:3: warning[deadcode.DeadStores]: Value stored to 'w' is never read + # 135| } + # 136| + # 137|-> w = data; /* no warning */ + # 138| } + # 139| + +Error: CHECKED_RETURN (CWE-252): [#def32] +dnsmasq-2.86test7/src/dbus.c:146: check_return: Calling "dbus_message_iter_init" without checking return value (as is done elsewhere 4 out of 5 times). +dnsmasq-2.86test7/src/dbus.c:460: example_checked: Example 1: "dbus_message_iter_init(message, &iter)" has its value checked in "dbus_message_iter_init(message, &iter)". +dnsmasq-2.86test7/src/dbus.c:573: example_checked: Example 2: "dbus_message_iter_init(message, &iter)" has its value checked in "dbus_message_iter_init(message, &iter)". +dnsmasq-2.86test7/src/dbus.c:257: example_checked: Example 3: "dbus_message_iter_init(message, &iter)" has its value checked in "dbus_message_iter_init(message, &iter)". +dnsmasq-2.86test7/src/dbus.c:427: example_checked: Example 4: "dbus_message_iter_init(message, &iter)" has its value checked in "dbus_message_iter_init(message, &iter)". + # 144| char *domain; + # 145| + # 146|-> dbus_message_iter_init(message, &iter); + # 147| + # 148| mark_servers(SERV_FROM_DBUS); + +Error: NEGATIVE_RETURNS (CWE-394): [#def33] +dnsmasq-2.86test7/src/dbus.c:547: negative_return_fn: Function "parse_hex((char *)hwaddr, dhcp_chaddr, 16, NULL, &hw_type)" returns a negative number. +dnsmasq-2.86test7/src/dbus.c:547: assign: Assigning: "hw_len" = "parse_hex((char *)hwaddr, dhcp_chaddr, 16, NULL, &hw_type)". +dnsmasq-2.86test7/src/dbus.c:551: negative_returns: "hw_len" is passed to a parameter that cannot be negative. + # 549| hw_type = ARPHRD_ETHER; + # 550| + # 551|-> lease_set_hwaddr(lease, dhcp_chaddr, clid, hw_len, hw_type, + # 552| clid_len, now, 0); + # 553| lease_set_expires(lease, expires, now); + +Error: CLANG_WARNING: [#def34] +dnsmasq-2.86test7/src/dbus.c:722:3: warning[deadcode.DeadStores]: Value stored to 'method' is never read + # 720| clear_cache_and_reload(dnsmasq_time()); + # 721| + # 722|-> method = user_data; /* no warning */ + # 723| + # 724| /* If no reply or no error, return nothing */ +--- + src/dbus.c | 21 +++++++++++++++------ + 1 file changed, 15 insertions(+), 6 deletions(-) + +diff --git a/src/dbus.c b/src/dbus.c +index cbdce9c..d746b9a 100644 +--- a/src/dbus.c ++++ b/src/dbus.c +@@ -114,7 +114,7 @@ static dbus_bool_t add_watch(DBusWatch *watch, void *data) + w->next = daemon->watches; + daemon->watches = w; + +- w = data; /* no warning */ ++ (void)data; /* no warning */ + return TRUE; + } + +@@ -134,16 +134,20 @@ static void remove_watch(DBusWatch *watch, void *data) + up = &(w->next); + } + +- w = data; /* no warning */ ++ (void)data; /* no warning */ + } + +-static void dbus_read_servers(DBusMessage *message) ++static DBusMessage* dbus_read_servers(DBusMessage *message) + { + DBusMessageIter iter; + union mysockaddr addr, source_addr; + char *domain; + +- dbus_message_iter_init(message, &iter); ++ if (!dbus_message_iter_init(message, &iter)) ++ { ++ return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, ++ "Failed to initialize dbus message iter"); ++ } + + mark_servers(SERV_FROM_DBUS); + +@@ -222,6 +226,7 @@ static void dbus_read_servers(DBusMessage *message) + + /* unlink and free anything still marked. */ + cleanup_servers(); ++ return NULL; + } + + #ifdef HAVE_LOOP +@@ -545,6 +550,10 @@ static DBusMessage *dbus_add_lease(DBusMessage* message) + "Invalid IP address '%s'", ipaddr); + + hw_len = parse_hex((char*)hwaddr, dhcp_chaddr, DHCP_CHADDR_MAX, NULL, &hw_type); ++ if (hw_len < 0) ++ return dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS, ++ "Invalid HW address '%s'", hwaddr); ++ + if (hw_type == 0 && hw_len != 0) + hw_type = ARPHRD_ETHER; + +@@ -668,7 +677,7 @@ DBusHandlerResult message_handler(DBusConnection *connection, + #endif + else if (strcmp(method, "SetServers") == 0) + { +- dbus_read_servers(message); ++ reply = dbus_read_servers(message); + new_servers = 1; + } + else if (strcmp(method, "SetServersEx") == 0) +@@ -719,7 +728,7 @@ DBusHandlerResult message_handler(DBusConnection *connection, + if (clear_cache) + clear_cache_and_reload(dnsmasq_time()); + +- method = user_data; /* no warning */ ++ (void)user_data; /* no warning */ + + /* If no reply or no error, return nothing */ + if (!reply) +-- +2.31.1 + diff --git a/0009-Address-coverity-issues-detected-in-util.c.patch b/0009-Address-coverity-issues-detected-in-util.c.patch new file mode 100644 index 0000000..cc075c7 --- /dev/null +++ b/0009-Address-coverity-issues-detected-in-util.c.patch @@ -0,0 +1,110 @@ +From 7b975696a7bda5b86fcf168644f177544adb6fe9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= +Date: Fri, 3 Sep 2021 17:38:26 +0200 +Subject: [PATCH 09/15] Address coverity issues detected in util.c + +Error: CLANG_WARNING: [#def163] +dnsmasq-2.86test7/src/util.c:204:9: warning[deadcode.DeadStores]: Although the value stored to 'rc' is used in the enclosing expression, the value is never actually read from 'rc' + # 202| *nomem = 0; + # 203| + # 204|-> if (!(rc = check_name(in))) + # 205| return NULL; + # 206| + +Error: UNREACHABLE (CWE-561): [#def164] +dnsmasq-2.86test7/src/util.c:239: unreachable: This code cannot be reached: "if (ret = whine_malloc(strl...". + # 237| #endif + # 238| + # 239|-> if ((ret = whine_malloc(strlen(in)+1))) + # 240| strcpy(ret, in); + # 241| else if (nomem) + +Error: CLANG_WARNING: [#def165] +dnsmasq-2.86test7/src/util.c:531:2: warning[deadcode.DeadStores]: Value stored to 'p' is never read + # 529| p += sprintf(&buf[p], "%um", x); + # 530| if ((x = t%60)) + # 531|-> p += sprintf(&buf[p], "%us", x); + # 532| } + # 533| } + +Error: CPPCHECK_WARNING (CWE-456): [#def166] +dnsmasq-2.86test7/src/util.c:577: error[uninitvar]: Uninitialized variable: sav + # 575| for (j = 0; j < bytes; j++) + # 576| { + # 577|-> char sav = sav; + # 578| if (j < bytes - 1) + # 579| { + +Error: CLANG_WARNING: [#def167] +dnsmasq-2.86test7/src/util.c:577:9: warning[core.uninitialized.Assign]: Assigned value is garbage or undefined + # 575| for (j = 0; j < bytes; j++) + # 576| { + # 577|-> char sav = sav; + # 578| if (j < bytes - 1) + # 579| { + +Error: MISSING_RESTORE (CWE-573): [#def168] +dnsmasq-2.86test7/src/util.c:580: save: Saving non-local "in[(j + 1) * 2]" in local "sav". +dnsmasq-2.86test7/src/util.c:581: modify: Modifying non-local "in[(j + 1) * 2]". +dnsmasq-2.86test7/src/util.c:586: end_of_scope: Value of non-local "in[(j + 1) * 2]" that was saved in "sav" is not restored as it was along other paths. +dnsmasq-2.86test7/src/util.c:592: restore_example: The original value of non-local "in[(j + 1) * 2]" was restored here. + # 584| is illegal. */ + # 585| if (strchr(&in[j*2], '*')) + # 586|-> return -1; + # 587| out[i] = strtol(&in[j*2], NULL, 16); + # 588| mask = mask << 1; +--- + src/util.c | 13 +++++++++---- + 1 file changed, 9 insertions(+), 4 deletions(-) + +diff --git a/src/util.c b/src/util.c +index 1425764..8e69d55 100644 +--- a/src/util.c ++++ b/src/util.c +@@ -208,6 +208,8 @@ char *canonicalise(char *in, int *nomem) + /* older libidn2 strips underscores, so don't do IDN processing + if the name has an underscore (check_name() returned 2) */ + if (rc != 2) ++#else ++ (void)rc; + #endif + #if defined(HAVE_IDN) || defined(HAVE_LIBIDN2) + { +@@ -235,11 +237,14 @@ char *canonicalise(char *in, int *nomem) + return ret; + } + #endif +- ++ ++#if !defined(HAVE_LIBIDN2) || (defined(HAVE_LIBIDN2) && (!defined(IDN2_VERSION_NUMBER) || IDN2_VERSION_NUMBER < 0x02000003)) ++ /* If recent libidn2 is used, it cannot reach this code. */ + if ((ret = whine_malloc(strlen(in)+1))) + strcpy(ret, in); + else if (nomem) +- *nomem = 1; ++ *nomem = 1; ++#endif + + return ret; + } +@@ -528,7 +533,7 @@ void prettyprint_time(char *buf, unsigned int t) + if ((x = (t/60)%60)) + p += sprintf(&buf[p], "%um", x); + if ((x = t%60)) +- p += sprintf(&buf[p], "%us", x); ++ sprintf(&buf[p], "%us", x); + } + } + +@@ -574,7 +579,7 @@ int parse_hex(char *in, unsigned char *out, int maxlen, + int j, bytes = (1 + (r - in))/2; + for (j = 0; j < bytes; j++) + { +- char sav = sav; ++ char sav; + if (j < bytes - 1) + { + sav = in[(j+1)*2]; +-- +2.31.1 + diff --git a/0010-Fix-coverity-detected-issues-in-option.c.patch b/0010-Fix-coverity-detected-issues-in-option.c.patch new file mode 100644 index 0000000..a63ac41 --- /dev/null +++ b/0010-Fix-coverity-detected-issues-in-option.c.patch @@ -0,0 +1,236 @@ +From db835f8c40e83c6392e69ffc7f2cc500f7682dd4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= +Date: Fri, 3 Sep 2021 19:23:20 +0200 +Subject: [PATCH 10/15] Fix coverity detected issues in option.c + +Error: STRING_OVERFLOW (CWE-120): [#def99] +dnsmasq-2.86test7/src/option.c:801: fixed_size_dest: You might overrun the 100-character fixed-size string "buff" by copying "usage[i].arg" without checking the length. +# 799| if (usage[i].arg) +# 800| { +# 801|-> strcpy(buff, usage[i].arg); +# 802| for (j = 0; tab[j].handle; j++) +# 803| if (tab[j].handle == *(usage[i].arg)) + +Error: CLANG_WARNING: [#def100] +dnsmasq-2.86test7/src/option.c:962:3: warning[deadcode.DeadStores]: Value stored to 'domain' is never read +# 960| } +# 961| +# 962|-> domain += sprintf(domain, "in-addr.arpa"); +# 963| +# 964| return 1; + +Error: CLANG_WARNING: [#def101] +dnsmasq-2.86test7/src/option.c:981:3: warning[deadcode.DeadStores]: Value stored to 'domain' is never read +# 979| domain += sprintf(domain, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4); +# 980| } +# 981|-> domain += sprintf(domain, "ip6.arpa"); +# 982| +# 983| return 1; + +Error: RESOURCE_LEAK (CWE-772): [#def102] [important] +dnsmasq-2.86test7/src/option.c:1809: alloc_fn: Storage is returned from allocation function "opt_malloc". +dnsmasq-2.86test7/src/option.c:1809: var_assign: Assigning: "path" = storage returned from "opt_malloc(strlen(directory) + len + 2UL)". +dnsmasq-2.86test7/src/option.c:1810: noescape: Resource "path" is not freed or pointed-to in "strcpy". [Note: The source code implementation of the function has been overridden by a builtin model.] +dnsmasq-2.86test7/src/option.c:1811: noescape: Resource "path" is not freed or pointed-to in "strcat". [Note: The source code implementation of the function has been overridden by a builtin model.] +dnsmasq-2.86test7/src/option.c:1812: noescape: Resource "path" is not freed or pointed-to in "strcat". [Note: The source code implementation of the function has been overridden by a builtin model.] +dnsmasq-2.86test7/src/option.c:1815: noescape: Resource "path" is not freed or pointed-to in "stat". +dnsmasq-2.86test7/src/option.c:1809: overwrite_var: Overwriting "path" in "path = opt_malloc(strlen(directory) + len + 2UL)" leaks the storage that "path" points to. +# 1807| continue; +# 1808| +# 1809|-> path = opt_malloc(strlen(directory) + len + 2); +# 1810| strcpy(path, directory); +# 1811| strcat(path, "/"); + +Error: RESOURCE_LEAK (CWE-772): [#def103] [important] +dnsmasq-2.86test7/src/option.c:1809: alloc_fn: Storage is returned from allocation function "opt_malloc". +dnsmasq-2.86test7/src/option.c:1809: var_assign: Assigning: "path" = storage returned from "opt_malloc(strlen(directory) + len + 2UL)". +dnsmasq-2.86test7/src/option.c:1810: noescape: Resource "path" is not freed or pointed-to in "strcpy". [Note: The source code implementation of the function has been overridden by a builtin model.] +dnsmasq-2.86test7/src/option.c:1811: noescape: Resource "path" is not freed or pointed-to in "strcat". [Note: The source code implementation of the function has been overridden by a builtin model.] +dnsmasq-2.86test7/src/option.c:1812: noescape: Resource "path" is not freed or pointed-to in "strcat". [Note: The source code implementation of the function has been overridden by a builtin model.] +dnsmasq-2.86test7/src/option.c:1815: noescape: Resource "path" is not freed or pointed-to in "stat". +dnsmasq-2.86test7/src/option.c:1858: leaked_storage: Variable "path" going out of scope leaks the storage it points to. +# 1856| free(files); +# 1857| } +# 1858|-> break; +# 1859| } +# 1860| + +Error: RESOURCE_LEAK (CWE-772): [#def104] [important] +dnsmasq-2.86test7/src/option.c:1996: alloc_fn: Storage is returned from allocation function "canonicalise_opt". +dnsmasq-2.86test7/src/option.c:1996: var_assign: Assigning: "name" = storage returned from "canonicalise_opt(arg)". +dnsmasq-2.86test7/src/option.c:1998: leaked_storage: Variable "name" going out of scope leaks the storage it points to. +# 1996| if (!(name = canonicalise_opt(arg)) || +# 1997| (comma && !(target = canonicalise_opt(comma)))) +# 1998|-> ret_err(_("bad MX name")); +# 1999| +# 2000| new = opt_malloc(sizeof(struct mx_srv_record)); + +Error: RESOURCE_LEAK (CWE-772): [#def106] [important] +dnsmasq-2.86test7/src/option.c:3477: alloc_fn: Storage is returned from allocation function "opt_malloc". +dnsmasq-2.86test7/src/option.c:3477: var_assign: Assigning: "new" = storage returned from "opt_malloc(96UL)". +dnsmasq-2.86test7/src/option.c:3618: leaked_storage: Variable "new" going out of scope leaks the storage it points to. +# 3616| sprintf(errstr, _("duplicate dhcp-host IP address %s"), +# 3617| daemon->addrbuff); +# 3618|-> return 0; +# 3619| } +# 3620| } + +Error: RESOURCE_LEAK (CWE-772): [#def108] [important] +dnsmasq-2.86test7/src/option.c:3781: alloc_fn: Storage is returned from allocation function "opt_malloc". +dnsmasq-2.86test7/src/option.c:3781: var_assign: Assigning: "new" = storage returned from "opt_malloc(32UL)". +dnsmasq-2.86test7/src/option.c:3786: leaked_storage: Variable "new" going out of scope leaks the storage it points to. +# 3784| +# 3785| if (!(comma = split(arg)) || (len = strlen(comma)) == 0) +# 3786|-> ret_err(gen_err); +# 3787| +# 3788| new->wildcard = 0; + +Error: RESOURCE_LEAK (CWE-772): [#def109] [important] +dnsmasq-2.86test7/src/option.c:3921: alloc_fn: Storage is returned from allocation function "opt_malloc". +dnsmasq-2.86test7/src/option.c:3921: var_assign: Assigning: "new" = storage returned from "opt_malloc(56UL)". +dnsmasq-2.86test7/src/option.c:3994: leaked_storage: Variable "new" going out of scope leaks the storage it points to. +# 3992| } +# 3993| +# 3994|-> ret_err(gen_err); +# 3995| } +# 3996| + +Error: CLANG_WARNING: [#def111] +dnsmasq-2.86test7/src/option.c:4693:25: warning[deadcode.DeadStores]: Value stored to 'tmp' during its initialization is never read +# 4691| if (!canon) +# 4692| { +# 4693|-> struct name_list *tmp = new->names, *next; +# 4694| for (tmp = new->names; tmp; tmp = next) +# 4695| +--- + src/option.c | 33 +++++++++++++++++++++------------ + 1 file changed, 21 insertions(+), 12 deletions(-) + +diff --git a/src/option.c b/src/option.c +index ffce9fc..11655fd 100644 +--- a/src/option.c ++++ b/src/option.c +@@ -798,7 +798,7 @@ static void do_usage(void) + + if (usage[i].arg) + { +- strcpy(buff, usage[i].arg); ++ safe_strncpy(buff, usage[i].arg, sizeof(buff)); + for (j = 0; tab[j].handle; j++) + if (tab[j].handle == *(usage[i].arg)) + sprintf(buff, "%d", tab[j].val); +@@ -959,7 +959,7 @@ static int domain_rev4(char *domain, struct in_addr addr, int msize) + return 0; + } + +- domain += sprintf(domain, "in-addr.arpa"); ++ sprintf(domain, "in-addr.arpa"); + + return 1; + } +@@ -978,7 +978,7 @@ static int domain_rev6(char *domain, struct in6_addr *addr, int msize) + int dig = ((unsigned char *)addr)[i>>3]; + domain += sprintf(domain, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4); + } +- domain += sprintf(domain, "ip6.arpa"); ++ sprintf(domain, "ip6.arpa"); + + return 1; + } +@@ -1829,6 +1829,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma + new->next = li; + *up = new; + } ++ else ++ free(path); + + } + +@@ -1995,7 +1997,11 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma + + if (!(name = canonicalise_opt(arg)) || + (comma && !(target = canonicalise_opt(comma)))) +- ret_err(_("bad MX name")); ++ { ++ free(name); ++ free(target); ++ ret_err(_("bad MX name")); ++ } + + new = opt_malloc(sizeof(struct mx_srv_record)); + new->next = daemon->mxnames; +@@ -3616,6 +3622,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma + inet_ntop(AF_INET, &in, daemon->addrbuff, ADDRSTRLEN); + sprintf(errstr, _("duplicate dhcp-host IP address %s"), + daemon->addrbuff); ++ dhcp_config_free(new); + return 0; + } + } +@@ -3779,16 +3786,16 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma + + case LOPT_NAME_MATCH: /* --dhcp-name-match */ + { +- struct dhcp_match_name *new = opt_malloc(sizeof(struct dhcp_match_name)); +- struct dhcp_netid *id = opt_malloc(sizeof(struct dhcp_netid)); ++ struct dhcp_match_name *new; + ssize_t len; + + if (!(comma = split(arg)) || (len = strlen(comma)) == 0) + ret_err(gen_err); + ++ new = opt_malloc(sizeof(struct dhcp_match_name)); + new->wildcard = 0; +- new->netid = id; +- id->net = opt_string_alloc(set_prefix(arg)); ++ new->netid = opt_malloc(sizeof(struct dhcp_netid)); ++ new->netid->net = opt_string_alloc(set_prefix(arg)); + + if (comma[len-1] == '*') + { +@@ -3992,6 +3999,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma + } + } + ++ dhcp_netid_free(new->netid); ++ free(new); + ret_err(gen_err); + } + +@@ -4367,7 +4376,7 @@ err: + case LOPT_CNAME: /* --cname */ + { + struct cname *new; +- char *alias, *target, *last, *pen; ++ char *alias, *target=NULL, *last, *pen; + int ttl = -1; + + for (last = pen = NULL, comma = arg; comma; comma = split(comma)) +@@ -4382,13 +4391,13 @@ err: + if (pen != arg && atoi_check(last, &ttl)) + last = pen; + +- target = canonicalise_opt(last); +- + while (arg != last) + { + int arglen = strlen(arg); + alias = canonicalise_opt(arg); + ++ if (!target) ++ target = canonicalise_opt(last); + if (!alias || !target) + { + free(target); +@@ -4691,7 +4700,7 @@ err: + struct name_list *nl; + if (!canon) + { +- struct name_list *tmp = new->names, *next; ++ struct name_list *tmp, *next; + for (tmp = new->names; tmp; tmp = next) + { + next = tmp->next; +-- +2.31.1 + diff --git a/0011-Fix-coverity-detected-issue-in-radv.c.patch b/0011-Fix-coverity-detected-issue-in-radv.c.patch new file mode 100644 index 0000000..845de43 --- /dev/null +++ b/0011-Fix-coverity-detected-issue-in-radv.c.patch @@ -0,0 +1,54 @@ +From 9c088b29dcdb8a3e013120d8272a6e0314a8f3df Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= +Date: Fri, 3 Sep 2021 19:29:23 +0200 +Subject: [PATCH 11/15] Fix coverity detected issue in radv.c + +Error: NULL_RETURNS (CWE-476): [#def114] +dnsmasq-2.86test7/src/radv.c:748: returned_null: "expand" returns "NULL" (checked 10 out of 11 times). +dnsmasq-2.86test7/src/radv.c:748: var_assigned: Assigning: "p" = "NULL" return value from "expand". +dnsmasq-2.86test7/src/radv.c:749: dereference: Dereferencing a pointer that might be "NULL" "p" when calling "memset". [Note: The source code implementation of the function has been overridden by a builtin model.] +dnsmasq-2.86test7/src/outpacket.c:83: example_checked: Example 1: "expand(len)" has its value checked in "p = expand(len)". +dnsmasq-2.86test7/src/outpacket.c:109: example_checked: Example 2: "expand(1UL)" has its value checked in "p = expand(1UL)". +dnsmasq-2.86test7/src/radv.c:269: example_checked: Example 3: "expand(16UL)" has its value checked in "ra = expand(16UL)". +dnsmasq-2.86test7/src/radv.c:363: example_checked: Example 4: "expand(32UL)" has its value checked in "opt = expand(32UL)". +dnsmasq-2.86test7/src/radv.c:708: example_checked: Example 5: "expand(32UL)" has its value checked in "opt = expand(32UL)". + # 747| int len = (maclen + 9) >> 3; + # 748| unsigned char *p = expand(len << 3); + # 749|-> memset(p, 0, len << 3); + # 750| *p++ = ICMP6_OPT_SOURCE_MAC; + # 751| *p++ = len; + +Error: NULL_RETURNS (CWE-476): [#def115] +dnsmasq-2.86test7/src/radv.c:748: returned_null: "expand" returns "NULL" (checked 10 out of 11 times). +dnsmasq-2.86test7/src/radv.c:748: var_assigned: Assigning: "p" = "NULL" return value from "expand". +dnsmasq-2.86test7/src/radv.c:750: dereference: Incrementing a pointer which might be null: "p". +dnsmasq-2.86test7/src/outpacket.c:83: example_checked: Example 1: "expand(len)" has its value checked in "p = expand(len)". +dnsmasq-2.86test7/src/outpacket.c:109: example_checked: Example 2: "expand(1UL)" has its value checked in "p = expand(1UL)". +dnsmasq-2.86test7/src/radv.c:269: example_checked: Example 3: "expand(16UL)" has its value checked in "ra = expand(16UL)". +dnsmasq-2.86test7/src/radv.c:363: example_checked: Example 4: "expand(32UL)" has its value checked in "opt = expand(32UL)". +dnsmasq-2.86test7/src/radv.c:708: example_checked: Example 5: "expand(32UL)" has its value checked in "opt = expand(32UL)". + # 748| unsigned char *p = expand(len << 3); + # 749| memset(p, 0, len << 3); + # 750|-> *p++ = ICMP6_OPT_SOURCE_MAC; + # 751| *p++ = len; + # 752| memcpy(p, mac, maclen); +--- + src/radv.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/src/radv.c b/src/radv.c +index 3255904..6d6fa32 100644 +--- a/src/radv.c ++++ b/src/radv.c +@@ -746,6 +746,8 @@ static int add_lla(int index, unsigned int type, char *mac, size_t maclen, void + add 7 to round up */ + int len = (maclen + 9) >> 3; + unsigned char *p = expand(len << 3); ++ if (!p) ++ return 1; + memset(p, 0, len << 3); + *p++ = ICMP6_OPT_SOURCE_MAC; + *p++ = len; +-- +2.31.1 + diff --git a/0012-Fix-coverity-detected-issues-in-cache.c.patch b/0012-Fix-coverity-detected-issues-in-cache.c.patch new file mode 100644 index 0000000..e88c64a --- /dev/null +++ b/0012-Fix-coverity-detected-issues-in-cache.c.patch @@ -0,0 +1,41 @@ +From 957b2b25238d82a6c3afced2ff0423ad171fb22e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= +Date: Fri, 3 Sep 2021 20:10:37 +0200 +Subject: [PATCH 12/15] Fix coverity detected issues in cache.c + +Error: UNINIT (CWE-457): [#def27] +dnsmasq-2.86test7/src/cache.c:1193: var_decl: Declaring variable "lrec" without initializer. +dnsmasq-2.86test7/src/cache.c:1315: uninit_use_in_call: Using uninitialized value "lrec.ttd" when calling "make_non_terminals". + # 1313| { + # 1314| lrec.name.namep = txt->name; + # 1315|-> make_non_terminals(&lrec); + # 1316| } + # 1317| + +Error: CLANG_WARNING: [#def29] +dnsmasq-2.86test7/src/cache.c:1552:15: warning[core.uninitialized.Assign]: Assigned value is garbage or undefined + # 1550| { + # 1551| crecp->flags = (source->flags | F_NAMEP) & ~(F_IPV4 | F_IPV6 | F_CNAME | F_SRV | F_DNSKEY | F_DS | F_REVERSE); + # 1552|-> crecp->ttd = source->ttd; + # 1553| crecp->name.namep = name; + # 1554| +--- + src/cache.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/cache.c b/src/cache.c +index 97c51a7..6722fa6 100644 +--- a/src/cache.c ++++ b/src/cache.c +@@ -1188,7 +1188,7 @@ void cache_reload(void) + struct host_record *hr; + struct name_list *nl; + struct cname *a; +- struct crec lrec; ++ struct crec lrec = { 0, }; + struct mx_srv_record *mx; + struct txt_record *txt; + struct interface_name *intr; +-- +2.31.1 + diff --git a/0013-Fix-coverity-issues-detected-in-domain-match.c.patch b/0013-Fix-coverity-issues-detected-in-domain-match.c.patch new file mode 100644 index 0000000..60df62b --- /dev/null +++ b/0013-Fix-coverity-issues-detected-in-domain-match.c.patch @@ -0,0 +1,134 @@ +From 0dafe990a1395d597bc6022c3936769f7a0ddea7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= +Date: Fri, 3 Sep 2021 21:16:22 +0200 +Subject: [PATCH 13/15] Fix coverity issues detected in domain-match.c + +Error: CHECKED_RETURN (CWE-252): [#def28] +dnsmasq-2.86rc3/src/domain-match.c:414: check_return: Calling "add_resource_record" without checking return value (as is done elsewhere 44 out of 46 times). +dnsmasq-2.86rc3/src/auth.c:214: example_checked: Example 1: "add_resource_record(header, limit, &trunc, nameoffset, &ansp, dnsmasq_daemon->auth_ttl, NULL, 12, 1, "d", intr->name)" has its value checked in "add_resource_record(header, limit, &trunc, nameoffset, &ansp, dnsmasq_daemon->auth_ttl, NULL, 12, 1, "d", intr->name)". +dnsmasq-2.86rc3/src/auth.c:239: example_checked: Example 2: "add_resource_record(header, limit, &trunc, nameoffset, &ansp, dnsmasq_daemon->auth_ttl, NULL, 12, 1, "d", name)" has its value checked in "add_resource_record(header, limit, &trunc, nameoffset, &ansp, dnsmasq_daemon->auth_ttl, NULL, 12, 1, "d", name)". +dnsmasq-2.86rc3/src/rfc1035.c:1463: example_checked: Example 3: "add_resource_record(header, limit, &trunc, nameoffset, &ansp, crec_ttl(crecp, now), &nameoffset, 5, 1, "d", cname_target)" has its value checked in "add_resource_record(header, limit, &trunc, nameoffset, &ansp, crec_ttl(crecp, now), &nameoffset, 5, 1, "d", cname_target)". +dnsmasq-2.86rc3/src/rfc1035.c:1500: example_checked: Example 4: "add_resource_record(header, limit, &trunc, nameoffset, &ansp, ttl, NULL, 16, t->class, "t", t->len, t->txt)" has its value checked in "add_resource_record(header, limit, &trunc, nameoffset, &ansp, ttl, NULL, 16, t->class, "t", t->len, t->txt)". +dnsmasq-2.86rc3/src/rfc1035.c:2021: example_checked: Example 5: "add_resource_record(header, limit, NULL, rec->offset, &ansp, crec_ttl(crecp, now), NULL, type, 1, ((crecp->flags & 0x80U) ? "4" : "6"), &crecp->addr)" has its value checked in "add_resource_record(header, limit, NULL, rec->offset, &ansp, crec_ttl(crecp, now), NULL, type, 1, ((crecp->flags & 0x80U) ? "4" : "6"), &crecp->addr)". + # 412| + # 413| header->ancount = htons(ntohs(header->ancount) + 1); + # 414|-> add_resource_record(header, limit, &trunc, sizeof(struct dns_header), &p, daemon->local_ttl, NULL, T_A, C_IN, "4", &addr); + # 415| log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV6, name, (union all_addr *)&addr, NULL); + # 416| } + +Error: CHECKED_RETURN (CWE-252): [#def29] +dnsmasq-2.86rc3/src/domain-match.c:429: check_return: Calling "add_resource_record" without checking return value (as is done elsewhere 44 out of 46 times). +dnsmasq-2.86rc3/src/auth.c:214: example_checked: Example 1: "add_resource_record(header, limit, &trunc, nameoffset, &ansp, dnsmasq_daemon->auth_ttl, NULL, 12, 1, "d", intr->name)" has its value checked in "add_resource_record(header, limit, &trunc, nameoffset, &ansp, dnsmasq_daemon->auth_ttl, NULL, 12, 1, "d", intr->name)". +dnsmasq-2.86rc3/src/auth.c:239: example_checked: Example 2: "add_resource_record(header, limit, &trunc, nameoffset, &ansp, dnsmasq_daemon->auth_ttl, NULL, 12, 1, "d", name)" has its value checked in "add_resource_record(header, limit, &trunc, nameoffset, &ansp, dnsmasq_daemon->auth_ttl, NULL, 12, 1, "d", name)". +dnsmasq-2.86rc3/src/rfc1035.c:1463: example_checked: Example 3: "add_resource_record(header, limit, &trunc, nameoffset, &ansp, crec_ttl(crecp, now), &nameoffset, 5, 1, "d", cname_target)" has its value checked in "add_resource_record(header, limit, &trunc, nameoffset, &ansp, crec_ttl(crecp, now), &nameoffset, 5, 1, "d", cname_target)". +dnsmasq-2.86rc3/src/rfc1035.c:1500: example_checked: Example 4: "add_resource_record(header, limit, &trunc, nameoffset, &ansp, ttl, NULL, 16, t->class, "t", t->len, t->txt)" has its value checked in "add_resource_record(header, limit, &trunc, nameoffset, &ansp, ttl, NULL, 16, t->class, "t", t->len, t->txt)". +dnsmasq-2.86rc3/src/rfc1035.c:2021: example_checked: Example 5: "add_resource_record(header, limit, NULL, rec->offset, &ansp, crec_ttl(crecp, now), NULL, type, 1, ((crecp->flags & 0x80U) ? "4" : "6"), &crecp->addr)" has its value checked in "add_resource_record(header, limit, NULL, rec->offset, &ansp, crec_ttl(crecp, now), NULL, type, 1, ((crecp->flags & 0x80U) ? "4" : "6"), &crecp->addr)". + # 427| + # 428| header->ancount = htons(ntohs(header->ancount) + 1); + # 429|-> add_resource_record(header, limit, &trunc, sizeof(struct dns_header), &p, daemon->local_ttl, NULL, T_AAAA, C_IN, "6", &addr); + # 430| log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV4, name, (union all_addr *)&addr, NULL); + # 431| } + +Error: NULL_RETURNS (CWE-476): [#def30] +dnsmasq-2.86rc3/src/domain-match.c:611: returned_null: "whine_malloc" returns "NULL" (checked 72 out of 76 times). +dnsmasq-2.86rc3/src/domain-match.c:611: var_assigned: Assigning: "alloc_domain" = "NULL" return value from "whine_malloc". +dnsmasq-2.86rc3/src/domain-match.c:620: dereference: Dereferencing a pointer that might be "NULL" "alloc_domain" when calling "hostname_isequal". +dnsmasq-2.86rc3/src/arp.c:88: example_checked: Example 1: "whine_malloc(48UL)" has its value checked in "arp = whine_malloc(48UL)". +dnsmasq-2.86rc3/src/blockdata.c:24: example_assign: Example 2: Assigning: "new" = return value from "whine_malloc(n * 48UL)". +dnsmasq-2.86rc3/src/blockdata.c:26: example_checked: Example 2 (cont.): "new" has its value checked in "new". +dnsmasq-2.86rc3/src/cache.c:1545: example_assign: Example 3: Assigning: "crecp" = return value from "whine_malloc(70UL)". +dnsmasq-2.86rc3/src/cache.c:1547: example_checked: Example 3 (cont.): "crecp" has its value checked in "crecp". +dnsmasq-2.86rc3/src/forward.c:1791: example_assign: Example 4: Assigning: "packet" = return value from "whine_malloc(66573UL)". +dnsmasq-2.86rc3/src/forward.c:1795: example_checked: Example 4 (cont.): "packet" has its value checked in "packet". +dnsmasq-2.86rc3/src/inotify.c:186: example_checked: Example 5: "whine_malloc(lendir + lenfile + 2UL)" has its value checked in "path = whine_malloc(lendir + lenfile + 2UL)". + # 618| if (flags & SERV_IS_LOCAL) + # 619| for (serv = daemon->servers; serv; serv = serv->next) + # 620|-> if ((serv->flags & SERV_MARK) && + # 621| hostname_isequal(alloc_domain, serv->domain)) + # 622| break; + +Error: RESOURCE_LEAK (CWE-772): [#def31] [important] +dnsmasq-2.86rc3/src/domain-match.c:611: alloc_fn: Storage is returned from allocation function "whine_malloc". +dnsmasq-2.86rc3/src/domain-match.c:611: var_assign: Assigning: "alloc_domain" = storage returned from "whine_malloc(1UL)". +dnsmasq-2.86rc3/src/domain-match.c:620: noescape: Resource "alloc_domain" is not freed or pointed-to in "hostname_isequal". +dnsmasq-2.86rc3/src/domain-match.c:646: leaked_storage: Variable "alloc_domain" going out of scope leaks the storage it points to. + # 644| + # 645| if (!(serv = whine_malloc(size))) + # 646|-> return 0; + # 647| + # 648| if (flags & SERV_IS_LOCAL) + +Error: NULL_RETURNS (CWE-476): [#def32] +dnsmasq-2.86rc3/src/domain-match.c:611: returned_null: "whine_malloc" returns "NULL" (checked 72 out of 76 times). +dnsmasq-2.86rc3/src/domain-match.c:611: var_assigned: Assigning: "alloc_domain" = "NULL" return value from "whine_malloc". +dnsmasq-2.86rc3/src/domain-match.c:674: dereference: Dereferencing a pointer that might be "NULL" "alloc_domain" when calling "strlen". +dnsmasq-2.86rc3/src/arp.c:88: example_checked: Example 1: "whine_malloc(48UL)" has its value checked in "arp = whine_malloc(48UL)". +dnsmasq-2.86rc3/src/blockdata.c:24: example_assign: Example 2: Assigning: "new" = return value from "whine_malloc(n * 48UL)". +dnsmasq-2.86rc3/src/blockdata.c:26: example_checked: Example 2 (cont.): "new" has its value checked in "new". +dnsmasq-2.86rc3/src/cache.c:1545: example_assign: Example 3: Assigning: "crecp" = return value from "whine_malloc(70UL)". +dnsmasq-2.86rc3/src/cache.c:1547: example_checked: Example 3 (cont.): "crecp" has its value checked in "crecp". +dnsmasq-2.86rc3/src/forward.c:1791: example_assign: Example 4: Assigning: "packet" = return value from "whine_malloc(66573UL)". +dnsmasq-2.86rc3/src/forward.c:1795: example_checked: Example 4 (cont.): "packet" has its value checked in "packet". +dnsmasq-2.86rc3/src/inotify.c:186: example_checked: Example 5: "whine_malloc(lendir + lenfile + 2UL)" has its value checked in "path = whine_malloc(lendir + lenfile + 2UL)". + # 672| serv->flags = flags; + # 673| serv->domain = alloc_domain; + # 674|-> serv->domain_len = strlen(alloc_domain); + # 675| + # 676| if (flags & SERV_4ADDR) +--- + src/domain-match.c | 17 ++++++++++++----- + 1 file changed, 12 insertions(+), 5 deletions(-) + +diff --git a/src/domain-match.c b/src/domain-match.c +index f8e4796..7124c18 100644 +--- a/src/domain-match.c ++++ b/src/domain-match.c +@@ -411,7 +411,8 @@ size_t make_local_answer(int flags, int gotname, size_t size, struct dns_header + addr.addr4 = srv->addr; + + header->ancount = htons(ntohs(header->ancount) + 1); +- add_resource_record(header, limit, &trunc, sizeof(struct dns_header), &p, daemon->local_ttl, NULL, T_A, C_IN, "4", &addr); ++ if (!add_resource_record(header, limit, &trunc, sizeof(struct dns_header), &p, daemon->local_ttl, NULL, T_A, C_IN, "4", &addr)) ++ return 0; + log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV6, name, (union all_addr *)&addr, NULL); + } + +@@ -426,7 +427,8 @@ size_t make_local_answer(int flags, int gotname, size_t size, struct dns_header + addr.addr6 = srv->addr; + + header->ancount = htons(ntohs(header->ancount) + 1); +- add_resource_record(header, limit, &trunc, sizeof(struct dns_header), &p, daemon->local_ttl, NULL, T_AAAA, C_IN, "6", &addr); ++ if (!add_resource_record(header, limit, &trunc, sizeof(struct dns_header), &p, daemon->local_ttl, NULL, T_AAAA, C_IN, "6", &addr)) ++ return 0; + log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV4, name, (union all_addr *)&addr, NULL); + } + +@@ -609,9 +611,11 @@ int add_update_server(int flags, + + if (*domain == 0) + alloc_domain = whine_malloc(1); +- else if (!(alloc_domain = canonicalise((char *)domain, NULL))) ++ else ++ alloc_domain = canonicalise((char *)domain, NULL); ++ if (!alloc_domain) + return 0; +- ++ + /* See if there is a suitable candidate, and unmark + only do this for forwarding servers, not + address or local, to avoid delays on large numbers. */ +@@ -643,7 +647,10 @@ int add_update_server(int flags, + size = sizeof(struct server); + + if (!(serv = whine_malloc(size))) +- return 0; ++ { ++ free(alloc_domain); ++ return 0; ++ } + + if (flags & SERV_IS_LOCAL) + { +-- +2.31.1 + diff --git a/0014-Fix-coverity-detected-issues-in-dnsmasq.c.patch b/0014-Fix-coverity-detected-issues-in-dnsmasq.c.patch new file mode 100644 index 0000000..6069244 --- /dev/null +++ b/0014-Fix-coverity-detected-issues-in-dnsmasq.c.patch @@ -0,0 +1,133 @@ +From f476acbe3c2830e6ff0c50cc36d364a3f3f4fadb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= +Date: Fri, 3 Sep 2021 22:45:29 +0200 +Subject: [PATCH 14/15] Fix coverity detected issues in dnsmasq.c + +Error: DEADCODE (CWE-561): [#def12] +dnsmasq-2.86rc3/src/dnsmasq.c:37: assignment: Assigning: "bind_fallback" = "0". +dnsmasq-2.86rc3/src/dnsmasq.c:927: const: At condition "bind_fallback", the value of "bind_fallback" must be equal to 0. +dnsmasq-2.86rc3/src/dnsmasq.c:927: dead_error_condition: The condition "bind_fallback" cannot be true. +dnsmasq-2.86rc3/src/dnsmasq.c:928: dead_error_line: Execution cannot reach this statement: "my_syslog(4, "setting --bin...". +dnsmasq-2.86rc3/src/dnsmasq.c:928: effectively_constant: Local variable "bind_fallback" is assigned only once, to a constant value, making it effectively constant throughout its scope. If this is not the intent, examine the logic to see if there is a missing assignment that would make "bind_fallback" not remain constant. + # 926| + # 927| if (bind_fallback) + # 928|-> my_syslog(LOG_WARNING, _("setting --bind-interfaces option because of OS limitations")); + # 929| + # 930| if (option_bool(OPT_NOWILD)) + +Error: REVERSE_NEGATIVE (CWE-191): [#def13] +dnsmasq-2.86rc3/src/dnsmasq.c:383: negative_sink_in_call: Passing "dnsmasq_daemon->pxefd" to a parameter that cannot be negative. +dnsmasq-2.86rc3/src/dnsmasq.c:1086: check_after_sink: You might be using variable "dnsmasq_daemon->pxefd" before verifying that it is >= 0. + # 1084| { + # 1085| poll_listen(daemon->dhcpfd, POLLIN); + # 1086|-> if (daemon->pxefd != -1) + # 1087| poll_listen(daemon->pxefd, POLLIN); + # 1088| } + +Error: CHECKED_RETURN (CWE-252): [#def18] +dnsmasq-2.86rc3/src/dnsmasq.c:1582: check_return: Calling "fcntl(dnsmasq_daemon->helperfd, 4, i & 0xfffffffffffff7ff)" without checking return value. This library function may fail and return an error code. + # 1580| /* block in writes until all done */ + # 1581| if ((i = fcntl(daemon->helperfd, F_GETFL)) != -1) + # 1582|-> fcntl(daemon->helperfd, F_SETFL, i & ~O_NONBLOCK); + # 1583| do { + # 1584| helper_write(); + +Error: CHECKED_RETURN (CWE-252): [#def22] +dnsmasq-2.86rc3/src/dnsmasq.c:1991: check_return: Calling "fcntl(confd, 4, flags & 0xfffffffffffff7ff)" without checking return value. This library function may fail and return an error code. + # 1989| Reset that here. */ + # 1990| if ((flags = fcntl(confd, F_GETFL, 0)) != -1) + # 1991|-> fcntl(confd, F_SETFL, flags & ~O_NONBLOCK); + # 1992| + # 1993| buff = tcp_request(confd, now, &tcp_addr, netmask, auth_dns); + +Error: CHECKED_RETURN (CWE-252): [#def26] +dnsmasq-2.86rc3/src/dnssec.c:727: check_return: Calling "extract_name" without checking return value (as is done elsewhere 9 out of 10 times). +dnsmasq-2.86rc3/src/dnssec.c:459: example_checked: Example 1: "extract_name(header, plen, &p, keyname, 1, 0)" has its value checked in "extract_name(header, plen, &p, keyname, 1, 0)". +dnsmasq-2.86rc3/src/dnssec.c:269: example_checked: Example 2: "extract_name(header, plen, &state->ip, state->buff, 1, 0)" has its value checked in "extract_name(header, plen, &state->ip, state->buff, 1, 0)". +dnsmasq-2.86rc3/src/dnssec.c:569: example_checked: Example 3: "extract_name(header, plen, &p, keyname, 1, 0)" has its value checked in "extract_name(header, plen, &p, keyname, 1, 0)". +dnsmasq-2.86rc3/src/rfc1035.c:648: example_checked: Example 4: "extract_name(header, qlen, &p1, name, 1, 0)" has its value checked in "extract_name(header, qlen, &p1, name, 1, 0)". +dnsmasq-2.86rc3/src/rfc1035.c:787: example_checked: Example 5: "extract_name(header, qlen, &p1, name, 1, 0)" has its value checked in "extract_name(header, qlen, &p1, name, 1, 0)". + # 725| /* namebuff used for workspace above, restore to leave unchanged on exit */ + # 726| p = (unsigned char*)(rrset[0]); + # 727|-> extract_name(header, plen, &p, name, 1, 0); + # 728| + # 729| if (key) + +Error: CHECKED_RETURN (CWE-252): [#def27] +dnsmasq-2.86rc3/src/dnssec.c:1020: check_return: Calling "extract_name" without checking return value (as is done elsewhere 7 out of 8 times). +dnsmasq-2.86rc3/src/auth.c:140: example_checked: Example 1: "extract_name(header, qlen, &p, name, 1, 4)" has its value checked in "extract_name(header, qlen, &p, name, 1, 4)". +dnsmasq-2.86rc3/src/dnssec.c:771: example_checked: Example 2: "extract_name(header, plen, &p, name, 1, 4)" has its value checked in "extract_name(header, plen, &p, name, 1, 4)". +dnsmasq-2.86rc3/src/hash-questions.c:57: example_checked: Example 3: "extract_name(header, plen, &p, name, 1, 4)" has its value checked in "extract_name(header, plen, &p, name, 1, 4)". +dnsmasq-2.86rc3/src/rfc1035.c:1028: example_checked: Example 4: "extract_name(header, qlen, &p, name, 1, 4)" has its value checked in "extract_name(header, qlen, &p, name, 1, 4)". +dnsmasq-2.86rc3/src/rfc1035.c:1438: example_checked: Example 5: "extract_name(header, qlen, &p, name, 1, 4)" has its value checked in "extract_name(header, qlen, &p, name, 1, 4)". + # 1018| + # 1019| p = (unsigned char *)(header+1); + # 1020|-> extract_name(header, plen, &p, name, 1, 4); + # 1021| p += 4; /* qtype, qclass */ + # 1022| +--- + src/dnsmasq.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git a/src/dnsmasq.c b/src/dnsmasq.c +index 602daed..3e1bfe8 100644 +--- a/src/dnsmasq.c ++++ b/src/dnsmasq.c +@@ -34,7 +34,6 @@ static void poll_resolv(int force, int do_reload, time_t now); + + int main (int argc, char **argv) + { +- int bind_fallback = 0; + time_t now; + struct sigaction sigact; + struct iname *if_tmp; +@@ -59,6 +58,8 @@ int main (int argc, char **argv) + int did_bind = 0; + struct server *serv; + char *netlink_warn; ++#else ++ int bind_fallback = 0; + #endif + #if defined(HAVE_DHCP) || defined(HAVE_DHCP6) + struct dhcp_context *context; +@@ -377,7 +378,7 @@ int main (int argc, char **argv) + bindtodevice(bound_device, daemon->dhcpfd); + did_bind = 1; + } +- if (daemon->enable_pxe && bound_device) ++ if (daemon->enable_pxe && bound_device && daemon->pxefd != -1) + { + bindtodevice(bound_device, daemon->pxefd); + did_bind = 1; +@@ -920,8 +921,10 @@ int main (int argc, char **argv) + my_syslog(LOG_WARNING, _("warning: failed to change owner of %s: %s"), + daemon->log_file, strerror(log_err)); + ++#ifndef HAVE_LINUX_NETWORK + if (bind_fallback) + my_syslog(LOG_WARNING, _("setting --bind-interfaces option because of OS limitations")); ++#endif + + if (option_bool(OPT_NOWILD)) + warn_bound_listeners(); +@@ -1575,7 +1578,7 @@ static void async_event(int pipe, time_t now) + { + /* block in writes until all done */ + if ((i = fcntl(daemon->helperfd, F_GETFL)) != -1) +- fcntl(daemon->helperfd, F_SETFL, i & ~O_NONBLOCK); ++ while(retry_send(fcntl(daemon->helperfd, F_SETFL, i & ~O_NONBLOCK))); + do { + helper_write(); + } while (!helper_buf_empty() || do_script_run(now)); +@@ -1984,7 +1987,7 @@ static void check_dns_listeners(time_t now) + attribute from the listening socket. + Reset that here. */ + if ((flags = fcntl(confd, F_GETFL, 0)) != -1) +- fcntl(confd, F_SETFL, flags & ~O_NONBLOCK); ++ while(retry_send(fcntl(confd, F_SETFL, flags & ~O_NONBLOCK))); + + buff = tcp_request(confd, now, &tcp_addr, netmask, auth_dns); + +-- +2.31.1 + diff --git a/0015-Fix-coverity-issues-in-dnssec.c.patch b/0015-Fix-coverity-issues-in-dnssec.c.patch new file mode 100644 index 0000000..67b1d6d --- /dev/null +++ b/0015-Fix-coverity-issues-in-dnssec.c.patch @@ -0,0 +1,62 @@ +From 82c23fb1f0d9e46c6ce4bc4a57f0d377cc6089b7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= +Date: Fri, 3 Sep 2021 22:51:36 +0200 +Subject: [PATCH 15/15] Fix coverity issues in dnssec.c + +Error: CHECKED_RETURN (CWE-252): [#def26] +dnsmasq-2.86rc3/src/dnssec.c:727: check_return: Calling "extract_name" without checking return value (as is done elsewhere 9 out of 10 times). +dnsmasq-2.86rc3/src/dnssec.c:459: example_checked: Example 1: "extract_name(header, plen, &p, keyname, 1, 0)" has its value checked in "extract_name(header, plen, &p, keyname, 1, 0)". +dnsmasq-2.86rc3/src/dnssec.c:269: example_checked: Example 2: "extract_name(header, plen, &state->ip, state->buff, 1, 0)" has its value checked in "extract_name(header, plen, &state->ip, state->buff, 1, 0)". +dnsmasq-2.86rc3/src/dnssec.c:569: example_checked: Example 3: "extract_name(header, plen, &p, keyname, 1, 0)" has its value checked in "extract_name(header, plen, &p, keyname, 1, 0)". +dnsmasq-2.86rc3/src/rfc1035.c:648: example_checked: Example 4: "extract_name(header, qlen, &p1, name, 1, 0)" has its value checked in "extract_name(header, qlen, &p1, name, 1, 0)". +dnsmasq-2.86rc3/src/rfc1035.c:787: example_checked: Example 5: "extract_name(header, qlen, &p1, name, 1, 0)" has its value checked in "extract_name(header, qlen, &p1, name, 1, 0)". + # 725| /* namebuff used for workspace above, restore to leave unchanged on exit */ + # 726| p = (unsigned char*)(rrset[0]); + # 727|-> extract_name(header, plen, &p, name, 1, 0); + # 728| + # 729| if (key) + +Error: CHECKED_RETURN (CWE-252): [#def27] +dnsmasq-2.86rc3/src/dnssec.c:1020: check_return: Calling "extract_name" without checking return value (as is done elsewhere 7 out of 8 times). +dnsmasq-2.86rc3/src/auth.c:140: example_checked: Example 1: "extract_name(header, qlen, &p, name, 1, 4)" has its value checked in "extract_name(header, qlen, &p, name, 1, 4)". +dnsmasq-2.86rc3/src/dnssec.c:771: example_checked: Example 2: "extract_name(header, plen, &p, name, 1, 4)" has its value checked in "extract_name(header, plen, &p, name, 1, 4)". +dnsmasq-2.86rc3/src/hash-questions.c:57: example_checked: Example 3: "extract_name(header, plen, &p, name, 1, 4)" has its value checked in "extract_name(header, plen, &p, name, 1, 4)". +dnsmasq-2.86rc3/src/rfc1035.c:1028: example_checked: Example 4: "extract_name(header, qlen, &p, name, 1, 4)" has its value checked in "extract_name(header, qlen, &p, name, 1, 4)". +dnsmasq-2.86rc3/src/rfc1035.c:1438: example_checked: Example 5: "extract_name(header, qlen, &p, name, 1, 4)" has its value checked in "extract_name(header, qlen, &p, name, 1, 4)". + # 1018| + # 1019| p = (unsigned char *)(header+1); + # 1020|-> extract_name(header, plen, &p, name, 1, 4); + # 1021| p += 4; /* qtype, qclass */ + # 1022| +--- + src/dnssec.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/src/dnssec.c b/src/dnssec.c +index 94ebb6f..8800a5b 100644 +--- a/src/dnssec.c ++++ b/src/dnssec.c +@@ -724,7 +724,8 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in + + /* namebuff used for workspace above, restore to leave unchanged on exit */ + p = (unsigned char*)(rrset[0]); +- extract_name(header, plen, &p, name, 1, 0); ++ if (!extract_name(header, plen, &p, name, 1, 0)) ++ return STAT_BOGUS; + + if (key) + { +@@ -1017,7 +1018,9 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char + } + + p = (unsigned char *)(header+1); +- extract_name(header, plen, &p, name, 1, 4); ++ if (!extract_name(header, plen, &p, name, 1, 4)) ++ return STAT_BOGUS; ++ + p += 4; /* qtype, qclass */ + + /* If the key needed to validate the DS is on the same domain as the DS, we'll +-- +2.31.1 + diff --git a/dnsmasq.spec b/dnsmasq.spec index 7e74130..3af1202 100644 --- a/dnsmasq.spec +++ b/dnsmasq.spec @@ -41,8 +41,24 @@ Patch1: dnsmasq-2.77-underflow.patch # https://bugzilla.redhat.com/show_bug.cgi?id=1852373 Patch2: dnsmasq-2.81-configuration.patch Patch3: dnsmasq-2.78-fips.patch -# https://bugzilla.redhat.com/show_bug.cgi?id=1978718 -Patch4: dnsmasq-2.85-lease-hostname.patch + +Patch10: 0001-Retry-on-interrupted-error-in-tftp.patch +Patch11: 0002-Add-safety-checks-to-places-pointed-by-Coverity.patch +Patch12: 0003-Small-safeguard-to-unexpected-data.patch +Patch13: 0004-Fix-bunch-of-warnings-in-auth.c.patch +Patch14: 0005-Fix-few-coverity-warnings-in-lease-tools.patch +Patch15: 0006-Fix-coverity-formats-issues-in-blockdata.patch +Patch16: 0007-Retry-dhcp6-ping-on-interrupts.patch +Patch17: 0008-Fix-coverity-warnings-on-dbus.patch +Patch18: 0009-Address-coverity-issues-detected-in-util.c.patch +Patch19: 0010-Fix-coverity-detected-issues-in-option.c.patch +Patch20: 0011-Fix-coverity-detected-issue-in-radv.c.patch +Patch21: 0012-Fix-coverity-detected-issues-in-cache.c.patch +Patch22: 0013-Fix-coverity-issues-detected-in-domain-match.c.patch +Patch23: 0014-Fix-coverity-detected-issues-in-dnsmasq.c.patch +Patch24: 0015-Fix-coverity-issues-in-dnssec.c.patch + + Requires: nettle