]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- Fix that the processing of class responses does not have
authorW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Wed, 3 Jun 2026 10:14:30 +0000 (12:14 +0200)
committerW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Wed, 3 Jun 2026 10:14:30 +0000 (12:14 +0200)
  a heap use-after-free. That could happen if at least two
  distinct classes are configured for resolution. Thanks
  to Qifan Zhang, Palo Alto Networks for the report.
  In addition, thanks to Xin Wang, Jiapeng Li, and Jiajia
  Liu, Northwestern Polytechnical University, for also
  reporting this.

doc/Changelog
iterator/iterator.c
testdata/iter_class_any_merge.rpl [new file with mode: 0644]

index 0cf9f7b4a645f3f733130a100a22316ed0f7f311..25fd8266c93a3b3c0607cf3b50bb91135c8808b8 100644 (file)
@@ -1,3 +1,12 @@
+3 June 2026: Wouter
+       - Fix that the processing of class responses does not have
+         a heap use-after-free. That could happen if at least two
+         distinct classes are configured for resolution. Thanks
+         to Qifan Zhang, Palo Alto Networks for the report.
+         In addition, thanks to Xin Wang, Jiapeng Li, and Jiajia
+         Liu, Northwestern Polytechnical University, for also
+         reporting this.
+
 29 May 2026: Wouter
        - Fix header_seen detection for trust anchor files, so that it
          detects the id line.
index 25b4401bfb8b4b12a47e64d2dd24810f58a23e4d..723590955355a7334dd1231864ba2d2a69baa9dd 100644 (file)
@@ -3990,7 +3990,7 @@ processClassResponse(struct module_qstate* qstate, int id,
                /* if there are records, copy RCODE */
                /* lower sec_state if this message is lower */
                if(from->rep->rrset_count != 0) {
-                       size_t n = from->rep->rrset_count+to->rep->rrset_count;
+                       size_t i, n = from->rep->rrset_count+to->rep->rrset_count;
                        struct ub_packed_rrset_key** dest, **d;
                        /* copy appropriate rcode */
                        to->rep->flags = from->rep->flags;
@@ -4012,24 +4012,49 @@ processClassResponse(struct module_qstate* qstate, int id,
                        memcpy(dest, to->rep->rrsets, to->rep->an_numrrsets
                                * sizeof(dest[0]));
                        dest += to->rep->an_numrrsets;
-                       memcpy(dest, from->rep->rrsets, from->rep->an_numrrsets
-                               * sizeof(dest[0]));
+                       for(i=0; i<from->rep->an_numrrsets; i++) {
+                               dest[i] = packed_rrset_copy_region(
+                                       from->rep->rrsets[i], forq->region, 0);
+                               if(!dest[i]) {
+                                       log_err("malloc failed in collect ANY");
+                                       foriq->state = FINISHED_STATE;
+                                       return;
+                               }
+                       }
                        dest += from->rep->an_numrrsets;
                        /* copy NS */
                        memcpy(dest, to->rep->rrsets+to->rep->an_numrrsets,
                                to->rep->ns_numrrsets * sizeof(dest[0]));
                        dest += to->rep->ns_numrrsets;
-                       memcpy(dest, from->rep->rrsets+from->rep->an_numrrsets,
-                               from->rep->ns_numrrsets * sizeof(dest[0]));
+                       for(i=0; i<from->rep->ns_numrrsets; i++) {
+                               dest[i] = packed_rrset_copy_region(
+                                       from->rep->rrsets[
+                                       from->rep->an_numrrsets+i],
+                                       forq->region, 0);
+                               if(!dest[i]) {
+                                       log_err("malloc failed in collect ANY");
+                                       foriq->state = FINISHED_STATE;
+                                       return;
+                               }
+                       }
                        dest += from->rep->ns_numrrsets;
                        /* copy AR */
                        memcpy(dest, to->rep->rrsets+to->rep->an_numrrsets+
                                to->rep->ns_numrrsets,
                                to->rep->ar_numrrsets * sizeof(dest[0]));
                        dest += to->rep->ar_numrrsets;
-                       memcpy(dest, from->rep->rrsets+from->rep->an_numrrsets+
-                               from->rep->ns_numrrsets,
-                               from->rep->ar_numrrsets * sizeof(dest[0]));
+                       for(i=0; i<from->rep->ar_numrrsets; i++) {
+                               dest[i] = packed_rrset_copy_region(
+                                       from->rep->rrsets[
+                                       from->rep->an_numrrsets+
+                                       from->rep->ns_numrrsets+i],
+                                       forq->region, 0);
+                               if(!dest[i]) {
+                                       log_err("malloc failed in collect ANY");
+                                       foriq->state = FINISHED_STATE;
+                                       return;
+                               }
+                       }
                        /* update counts */
                        to->rep->rrsets = d;
                        to->rep->an_numrrsets += from->rep->an_numrrsets;
diff --git a/testdata/iter_class_any_merge.rpl b/testdata/iter_class_any_merge.rpl
new file mode 100644 (file)
index 0000000..19ad5d2
--- /dev/null
@@ -0,0 +1,195 @@
+; config options
+; The island of trust is at example.com
+server:
+       trust-anchor: "example.com.    3600    IN      DS      2854 3 1 46e4ffc6e9a4793b488954bd3f0cc6af0dfb201b"
+       val-override-date: "20070916134226"
+       target-fetch-policy: "0 0 0 0 0"
+       qname-minimisation: "no"
+       fake-sha1: yes
+       trust-anchor-signaling: no
+       minimal-responses: no
+       iter-scrub-promiscuous: no
+       root-hints:
+TEMPFILE_NAME class_in.hints
+TEMPFILE_CONTENTS class_in.hints
+; hints for dns CLASS IN
+. 3600 NS k.root-servers.net.
+k.root-servers.net. 3600 IN A 193.0.14.129
+TEMPFILE_END
+
+       root-hints:
+TEMPFILE_NAME class_ch.hints
+TEMPFILE_CONTENTS class_ch.hints
+; hints for dns CLASS CH
+. 3600 CH NS ns.ch.test.
+ns.ch.test. 3600 CH A 1.2.3.5
+TEMPFILE_END
+
+CONFIG_END
+
+SCENARIO_BEGIN Test lookup of class any responses from several classes.
+; It merges the responses.
+
+; K.ROOT-SERVERS.NET.
+RANGE_BEGIN 0 100
+       ADDRESS 193.0.14.129 
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+. IN NS
+SECTION ANSWER
+. IN NS        K.ROOT-SERVERS.NET.
+SECTION ADDITIONAL
+K.ROOT-SERVERS.NET.    IN      A       193.0.14.129
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION AUTHORITY
+com.   IN NS   a.gtld-servers.net.
+SECTION ADDITIONAL
+a.gtld-servers.net.    IN      A       192.5.6.30
+ENTRY_END
+RANGE_END
+
+; a.gtld-servers.net.
+RANGE_BEGIN 0 100
+       ADDRESS 192.5.6.30
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+com. IN NS
+SECTION ANSWER
+com.    IN NS   a.gtld-servers.net.
+SECTION ADDITIONAL
+a.gtld-servers.net.     IN      A       192.5.6.30
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION AUTHORITY
+example.com.   IN NS   ns.example.com.
+SECTION ADDITIONAL
+ns.example.com.                IN      A       1.2.3.4
+ENTRY_END
+RANGE_END
+
+; ns.example.com.
+RANGE_BEGIN 0 100
+       ADDRESS 1.2.3.4
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+example.com. IN NS
+SECTION ANSWER
+example.com.    IN NS   ns.example.com.
+example.com.    3600    IN      RRSIG   NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
+SECTION ADDITIONAL
+ns.example.com.         IN      A       1.2.3.4
+ns.example.com. 3600    IN      RRSIG   A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854}
+ENTRY_END
+
+; response to DNSKEY priming query
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+example.com. IN DNSKEY
+SECTION ANSWER
+example.com.    3600    IN      DNSKEY  256 3 3 ALXLUsWqUrY3JYER3T4TBJII s70j+sDS/UT2QRp61SE7S3E EXopNXoFE73JLRmvpi/UrOO/Vz4Se 6wXv/CYCKjGw06U4WRgR YXcpEhJROyNapmdIKSx hOzfLVE1gqA0PweZR8d tY3aNQSRn3sPpwJr6Mi /PqQKAMMrZ9ckJpf1+b QMOOvxgzz2U1GS18b3y ZKcgTMEaJzd/GZYzi/B N2DzQ0MsrSwYXfsNLFO Bbs8PJMW4LYIxeeOe6rUgkWOF 7CC9Dh/dduQ1QrsJhmZAEFfd6ByYV+ ;{id = 2854 (zsk), size = 1688b}
+example.com.    3600    IN      RRSIG   DNSKEY 3 2 3600 20070926134802 20070829134802 2854 example.com. MCwCFG1yhRNtTEa3Eno2zhVVuy2EJX3wAhQeLyUp6+UXcpC5qGNu9tkrTEgPUg== ;{id = 2854}
+SECTION AUTHORITY
+example.com.   IN NS   ns.example.com.
+example.com.    3600    IN      RRSIG   NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
+SECTION ADDITIONAL
+ns.example.com.                IN      A       1.2.3.4
+ns.example.com. 3600    IN      RRSIG   A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854}
+ENTRY_END
+
+; response to query of interest
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+www.example.com. IN A  10.20.30.40
+ns.example.com. 3600    IN      RRSIG   A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCQMyTjn7WWwpwAR1LlVeLpRgZGuQIUCcJDEkwAuzytTDRlYK7nIMwH1CM= ;{id = 2854}
+SECTION AUTHORITY
+example.com.   IN NS   ns.example.com.
+example.com.    3600    IN      RRSIG   NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
+SECTION ADDITIONAL
+ns.example.com.                IN      A       1.2.3.4
+www.example.com.        3600    IN      RRSIG   A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFC99iE9K5y2WNgI0gFvBWaTi9wm6AhUAoUqOpDtG5Zct+Qr9F3mSdnbc6V4= ;{id = 2854}
+ENTRY_END
+RANGE_END
+
+; ns.ch.test.
+RANGE_BEGIN 0 100
+       ADDRESS 1.2.3.5
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+. CH NS
+SECTION ANSWER
+. CH NS ns.ch.test.
+SECTION ADDITIONAL
+ns.ch.test. CH A 1.2.3.5
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+www.example.com. CH A
+SECTION ANSWER
+www.example.com. CH A 3.4.5.6
+ENTRY_END
+RANGE_END
+
+STEP 1 QUERY
+ENTRY_BEGIN
+REPLY RD DO
+SECTION QUESTION
+www.example.com. ANY A
+ENTRY_END
+
+; recursion happens here.
+STEP 10 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA DO NOERROR
+SECTION QUESTION
+www.example.com. ANY A
+SECTION ANSWER
+www.example.com. CH A 3.4.5.6
+www.example.com. IN A  10.20.30.40
+www.example.com.        3600    IN      RRSIG   A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFC99iE9K5y2WNgI0gFvBWaTi9wm6AhUAoUqOpDtG5Zct+Qr9F3mSdnbc6V4= ;{id = 2854}
+SECTION AUTHORITY
+example.com.   IN NS   ns.example.com.
+example.com.    3600    IN      RRSIG   NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
+SECTION ADDITIONAL
+ns.example.com.                IN      A       1.2.3.4
+ns.example.com. 3600    IN      RRSIG   A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCQMyTjn7WWwpwAR1LlVeLpRgZGuQIUCcJDEkwAuzytTDRlYK7nIMwH1CM= ;{id = 2854}
+ENTRY_END
+
+SCENARIO_END