diff --git a/SOURCES/dnsmasq-2.79-server-domain-fixup.patch b/SOURCES/dnsmasq-2.79-server-domain-fixup.patch new file mode 100644 index 0000000..2c19ac8 --- /dev/null +++ b/SOURCES/dnsmasq-2.79-server-domain-fixup.patch @@ -0,0 +1,99 @@ +From b027daaa8ef168122a712e5e4ec71642964d8f4d Mon Sep 17 00:00:00 2001 +From: rpm-build +Date: Mon, 22 Aug 2022 21:59:42 +0200 +Subject: [PATCH] Ensure also server_domains_cleanup is called always + +Fixes issue in patch dnsmasq-2.79-server-domain-rh1919894.patch. + +When /etc/resolv.conf is changed, dnsmasq reloads used servers. But it +does not call cleanup of server domains in this case. It might cause +serv_domain->last_server to become non-null, but pointing released +server. Ensure it is checked before any cleanup_servers() action always +and from all other places, like dbus setting. + +Caused unending loop in forward_query function, rhbz#2106361. +--- + src/network.c | 49 +++++++++++++++++++++++++------------------------ + 1 file changed, 25 insertions(+), 24 deletions(-) + +diff --git a/src/network.c b/src/network.c +index 1fa81ff..cf2f2e2 100644 +--- a/src/network.c ++++ b/src/network.c +@@ -1511,10 +1511,35 @@ void mark_servers(int flag) + } + } + ++static void server_domains_cleanup(void) ++{ ++ struct server_domain *sd, *tmp, **up; ++ ++ /* unlink and free anything still marked. */ ++ for (up = &daemon->server_domains, sd=*up; sd; sd = tmp) ++ { ++ tmp = sd->next; ++ if (sd->flags & SERV_MARK) ++ { ++ *up = sd->next; ++ if (sd->domain) ++ free(sd->domain); ++ free(sd); ++ } ++ else { ++ up = &sd->next; ++ if (sd->last_server && (sd->last_server->flags & SERV_MARK)) ++ sd->last_server = NULL; ++ } ++ } ++} ++ + void cleanup_servers(void) + { + struct server *serv, *tmp, **up; + ++ server_domains_cleanup(); ++ + /* unlink and free anything still marked. */ + for (serv = daemon->servers, up = &daemon->servers; serv; serv = tmp) + { +@@ -1537,29 +1562,6 @@ void cleanup_servers(void) + #endif + } + +-static void server_domains_cleanup(void) +-{ +- struct server_domain *sd, *tmp, **up; +- +- /* unlink and free anything still marked. */ +- for (up = &daemon->server_domains, sd=*up; sd; sd = tmp) +- { +- tmp = sd->next; +- if (sd->flags & SERV_MARK) +- { +- *up = sd->next; +- if (sd->domain) +- free(sd->domain); +- free(sd); +- } +- else { +- up = &sd->next; +- if (sd->last_server && (sd->last_server->flags & SERV_MARK)) +- sd->last_server = NULL; +- } +- } +-} +- + void add_update_server(int flags, + union mysockaddr *addr, + union mysockaddr *source_addr, +@@ -1849,7 +1851,6 @@ void check_servers(void) + up = &sfd->next; + } + +- server_domains_cleanup(); + cleanup_servers(); + } + +-- +2.37.2 + diff --git a/SOURCES/dnsmasq-2.87-CVE-2022-0934.patch b/SOURCES/dnsmasq-2.87-CVE-2022-0934.patch index afc36bb..585adf5 100644 --- a/SOURCES/dnsmasq-2.87-CVE-2022-0934.patch +++ b/SOURCES/dnsmasq-2.87-CVE-2022-0934.patch @@ -1,175 +1,172 @@ -From b0cb924292daecc1cc89fbd3911373eb468fc8f1 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= -Date: Tue, 22 Feb 2022 00:45:01 +0100 -Subject: [PATCH] Change message type by dedicated function +From 5d1b75b542f128f757606668a44ce60ebb3c47f0 Mon Sep 17 00:00:00 2001 +From: Simon Kelley +Date: Thu, 31 Mar 2022 21:35:20 +0100 +Subject: [PATCH] Fix write-after-free error in DHCPv6 code. CVE-2022-0934 + refers. -Long-term pointer to beginning of message does not work well. I case -outpacket is reallocated in any new_opt6() section, original outmsgtypep -pointer becomes invalid. Instead of using that pointer use dedicated -function, which will change just the first byte of the message. - -This makes sure correct beginning of packet is always used. --- - src/dnsmasq.h | 1 + - src/outpacket.c | 11 +++++++++++ - src/rfc3315.c | 29 ++++++++++++++--------------- - 3 files changed, 26 insertions(+), 15 deletions(-) + src/rfc3315.c | 48 +++++++++++++++++++++++++++--------------------- + 1 file changed, 27 insertions(+), 21 deletions(-) -diff --git a/src/dnsmasq.h b/src/dnsmasq.h -index 27ff86a..0749260 100644 ---- a/src/dnsmasq.h -+++ b/src/dnsmasq.h -@@ -1563,6 +1563,7 @@ void put_opt6_long(unsigned int val); - void put_opt6_short(unsigned int val); - void put_opt6_char(unsigned int val); - void put_opt6_string(char *s); -+void put_msgtype6(unsigned int val); - #endif - - /* radv.c */ -diff --git a/src/outpacket.c b/src/outpacket.c -index d20bd33..1c8f1bc 100644 ---- a/src/outpacket.c -+++ b/src/outpacket.c -@@ -115,4 +115,15 @@ void put_opt6_string(char *s) - put_opt6(s, strlen(s)); - } - -+void put_msgtype6(unsigned int val) -+{ -+ if (outpacket_counter == 0) -+ put_opt6_char(val); -+ else -+ { -+ unsigned char *p = daemon->outpacket.iov_base; -+ *p = val; -+ } -+} -+ - #endif diff --git a/src/rfc3315.c b/src/rfc3315.c -index 554b1fe..1f1aad8 100644 +index fbb6876..d2ebf15 100644 --- a/src/rfc3315.c +++ b/src/rfc3315.c -@@ -116,7 +116,6 @@ static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz, +@@ -33,9 +33,9 @@ struct state { + unsigned int mac_len, mac_type; + }; + +-static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz, ++static int dhcp6_maybe_relay(struct state *state, unsigned char *inbuff, size_t sz, + struct in6_addr *client_addr, int is_unicast, time_t now); +-static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_t sz, int is_unicast, time_t now); ++static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbuff, size_t sz, int is_unicast, time_t now); + static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_opts); + static void log6_packet(struct state *state, char *type, struct in6_addr *addr, char *string); + static void log6_quiet(struct state *state, char *type, struct in6_addr *addr, char *string); +@@ -104,12 +104,12 @@ unsigned short dhcp6_reply(struct dhcp_context *context, int interface, char *if + } + + /* This cost me blood to write, it will probably cost you blood to understand - srk. */ +-static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz, ++static int dhcp6_maybe_relay(struct state *state, unsigned char *inbuff, size_t sz, + struct in6_addr *client_addr, int is_unicast, time_t now) + { void *end = inbuff + sz; void *opts = inbuff + 34; - int msg_type = *((unsigned char *)inbuff); -- unsigned char *outmsgtypep; +- int msg_type = *((unsigned char *)inbuff); ++ int msg_type = *inbuff; + unsigned char *outmsgtypep; void *opt; struct dhcp_vendor *vendor; +@@ -259,15 +259,15 @@ static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz, + return 1; + } -@@ -178,9 +177,9 @@ static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz, - return 0; - - /* copy header stuff into reply message and set type to reply */ -- if (!(outmsgtypep = put_opt6(inbuff, 34))) -+ if (!put_opt6(inbuff, 34)) - return 0; -- *outmsgtypep = DHCP6RELAYREPL; -+ put_msgtype6(DHCP6RELAYREPL); - - /* look for relay options and set tags if found. */ - for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next) -@@ -249,7 +248,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ +-static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_t sz, int is_unicast, time_t now) ++static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbuff, size_t sz, int is_unicast, time_t now) + { + void *opt; +- int i, o, o1, start_opts; ++ int i, o, o1, start_opts, start_msg; + struct dhcp_opt *opt_cfg; struct dhcp_netid *tagif; struct dhcp_config *config = NULL; struct dhcp_netid known_id, iface_id, v6_id; - unsigned char *outmsgtypep; -+ unsigned char *xid; ++ unsigned char outmsgtype; struct dhcp_vendor *vendor; struct dhcp_context *context_tmp; struct dhcp_mac *mac_opt; -@@ -286,10 +285,10 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ +@@ -296,12 +296,13 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ + v6_id.next = state->tags; state->tags = &v6_id; - /* copy over transaction-id, and save pointer to message type */ +- /* copy over transaction-id, and save pointer to message type */ - if (!(outmsgtypep = put_opt6(inbuff, 4))) -+ if (!(xid = put_opt6(inbuff, 4))) ++ start_msg = save_counter(-1); ++ /* copy over transaction-id */ ++ if (!put_opt6(inbuff, 4)) return 0; start_opts = save_counter(-1); - state->xid = outmsgtypep[3] | outmsgtypep[2] << 8 | outmsgtypep[1] << 16; -+ state->xid = xid[3] | xid[2] << 8 | xid[1] << 16; - +- ++ state->xid = inbuff[3] | inbuff[2] << 8 | inbuff[1] << 16; ++ /* We're going to be linking tags from all context we use. mark them as unused so we don't link one twice and break the list */ -@@ -336,7 +335,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ + for (context_tmp = state->context; context_tmp; context_tmp = context_tmp->current) +@@ -347,7 +348,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ (msg_type == DHCP6REQUEST || msg_type == DHCP6RENEW || msg_type == DHCP6RELEASE || msg_type == DHCP6DECLINE)) { - *outmsgtypep = DHCP6REPLY; -+ put_msgtype6(DHCP6REPLY); ++ outmsgtype = DHCP6REPLY; o1 = new_opt6(OPTION6_STATUS_CODE); put_opt6_short(DHCP6USEMULTI); put_opt6_string("Use multicast"); -@@ -600,11 +599,11 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ +@@ -619,11 +620,11 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ struct dhcp_netid *solicit_tags; struct dhcp_context *c; - *outmsgtypep = DHCP6ADVERTISE; -+ put_msgtype6(DHCP6ADVERTISE); ++ outmsgtype = DHCP6ADVERTISE; if (opt6_find(state->packet_options, state->end, OPTION6_RAPID_COMMIT, 0)) { - *outmsgtypep = DHCP6REPLY; -+ put_msgtype6(DHCP6REPLY); ++ outmsgtype = DHCP6REPLY; state->lease_allocate = 1; o = new_opt6(OPTION6_RAPID_COMMIT); end_opt6(o); -@@ -876,7 +875,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ +@@ -826,7 +827,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ int start = save_counter(-1); /* set reply message type */ - *outmsgtypep = DHCP6REPLY; -+ put_msgtype6(DHCP6REPLY); ++ outmsgtype = DHCP6REPLY; state->lease_allocate = 1; log6_quiet(state, "DHCPREQUEST", NULL, ignore ? _("ignored") : NULL); -@@ -992,7 +991,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ +@@ -938,7 +939,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ case DHCP6RENEW: { /* set reply message type */ - *outmsgtypep = DHCP6REPLY; -+ put_msgtype6(DHCP6REPLY); ++ outmsgtype = DHCP6REPLY; log6_quiet(state, "DHCPRENEW", NULL, NULL); -@@ -1104,7 +1103,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ +@@ -1050,7 +1051,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ int good_addr = 0; /* set reply message type */ - *outmsgtypep = DHCP6REPLY; -+ put_msgtype6(DHCP6REPLY); ++ outmsgtype = DHCP6REPLY; log6_quiet(state, "DHCPCONFIRM", NULL, NULL); -@@ -1168,7 +1167,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ +@@ -1114,7 +1115,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ log6_quiet(state, "DHCPINFORMATION-REQUEST", NULL, ignore ? _("ignored") : state->hostname); if (ignore) return 0; - *outmsgtypep = DHCP6REPLY; -+ put_msgtype6(DHCP6REPLY); ++ outmsgtype = DHCP6REPLY; tagif = add_options(state, 1); break; } -@@ -1177,7 +1176,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ +@@ -1123,7 +1124,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ case DHCP6RELEASE: { /* set reply message type */ - *outmsgtypep = DHCP6REPLY; -+ put_msgtype6(DHCP6REPLY); ++ outmsgtype = DHCP6REPLY; log6_quiet(state, "DHCPRELEASE", NULL, NULL); -@@ -1242,7 +1241,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ +@@ -1188,7 +1189,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ case DHCP6DECLINE: { /* set reply message type */ - *outmsgtypep = DHCP6REPLY; -+ put_msgtype6(DHCP6REPLY); ++ outmsgtype = DHCP6REPLY; log6_quiet(state, "DHCPDECLINE", NULL, NULL); +@@ -1268,7 +1269,12 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ + } + + } +- ++ ++ /* Fill in the message type. Note that we store the offset, ++ not a direct pointer, since the packet memory may have been ++ reallocated. */ ++ ((unsigned char *)(daemon->outpacket.iov_base))[start_msg] = outmsgtype; ++ + log_tags(tagif, state->xid); + log6_opts(0, state->xid, daemon->outpacket.iov_base + start_opts, daemon->outpacket.iov_base + save_counter(-1)); + -- -2.34.1 +2.39.1 diff --git a/SPECS/dnsmasq.spec b/SPECS/dnsmasq.spec index be042ca..fc8548b 100644 --- a/SPECS/dnsmasq.spec +++ b/SPECS/dnsmasq.spec @@ -20,7 +20,7 @@ Name: dnsmasq Version: 2.85 -Release: 4%{?extraversion:.%{extraversion}}%{?dist} +Release: 6%{?extraversion:.%{extraversion}}%{?dist} Summary: A lightweight DHCP/caching DNS server License: GPLv2 or GPLv3 @@ -47,7 +47,10 @@ Patch4: dnsmasq-2.79-server-domain-rh1919894.patch # https://lists.thekelleys.org.uk/pipermail/dnsmasq-discuss/2021q3/015640.html Patch5: dnsmasq-2.86-alternative-lease.patch Patch6: dnsmasq-2.86-dhcpv6-client-arch.patch +# http://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=commit;h=03345ecefeb0d82e3c3a4c28f27c3554f0611b39 Patch7: dnsmasq-2.87-CVE-2022-0934.patch +# Downstream only patch; fixes Patch4 change +Patch8: dnsmasq-2.79-server-domain-fixup.patch # This is workaround to nettle bug #1549190 # https://bugzilla.redhat.com/show_bug.cgi?id=1549190 @@ -191,6 +194,12 @@ install -Dpm 644 %{SOURCE2} %{buildroot}%{_sysusersdir}/%{name}.conf %{_mandir}/man1/dhcp_* %changelog +* Thu Jan 26 2023 Petr Menšík - 2.85-6 +- Use upstream change for CVE-2022-0934 (#2126586) + +* Mon Aug 22 2022 Petr Menšík - 2.85-5 +- Prevent endless loop in forward_query (#2120711) + * Fri Mar 25 2022 Petr Menšík - 2.85-4 - Prevent use after free in dhcp6_no_relay (CVE-2022-0934)