0001-QDnsLookup-Unix-make-sure-we-don-t-overflow-the-buff.patch 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. From fc233efad86101d49cd312b16c5a25e6a017e977 Mon Sep 17 00:00:00 2001
  2. From: Thiago Macieira <thiago.macieira@intel.com>
  3. Date: Thu, 11 May 2023 21:40:15 -0700
  4. Subject: [PATCH] QDnsLookup/Unix: make sure we don't overflow the buffer
  5. MIME-Version: 1.0
  6. Content-Type: text/plain; charset=UTF-8
  7. Content-Transfer-Encoding: 8bit
  8. The DNS Records are variable length and encode their size in 16 bits
  9. before the Record Data (RDATA). Ensure that both the RDATA and the
  10. Record header fields before it fall inside the buffer we have.
  11. Additionally reject any replies containing more than one query records.
  12. [ChangeLog][QtNetwork][QDnsLookup] Fixed a bug that could cause a buffer
  13. overflow in Unix systems while parsing corrupt, malicious, or truncated
  14. replies.
  15. Pick-to: 5.15 6.2 6.5 6.5.1
  16. Change-Id: I3e3bfef633af4130a03afffd175e4b9547654b95
  17. Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
  18. Reviewed-by: Jani Heikkinen <jani.heikkinen@qt.io>
  19. Fixes: https://security-tracker.debian.org/tracker/CVE-2023-33285
  20. Upstream: https://codereview.qt-project.org/gitweb?p=qt/qtbase.git;a=commitdiff;h=7dba2c87619d558a61a30eb30cc1d9c3fe6df94c
  21. [Thomas: changes needed to backport on 6.4.3: use local_dn_expand()
  22. instead of dn_expand(), since we didn't backport the changes in
  23. 68b625901f9eb7c34e3d7aa302e1c0a454d3190b that are too invasive]
  24. Signed-off-by: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
  25. ---
  26. src/network/kernel/qdnslookup_unix.cpp | 31 +++++++++++++++++++++-----
  27. 1 file changed, 25 insertions(+), 6 deletions(-)
  28. diff --git a/src/network/kernel/qdnslookup_unix.cpp b/src/network/kernel/qdnslookup_unix.cpp
  29. index 75f7c6c440e..de0113494fc 100644
  30. --- a/src/network/kernel/qdnslookup_unix.cpp
  31. +++ b/src/network/kernel/qdnslookup_unix.cpp
  32. @@ -193,7 +193,6 @@ void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestN
  33. // responseLength in case of error, we still can extract the
  34. // exact error code from the response.
  35. HEADER *header = (HEADER*)response;
  36. - const int answerCount = ntohs(header->ancount);
  37. switch (header->rcode) {
  38. case NOERROR:
  39. break;
  40. @@ -226,18 +225,31 @@ void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestN
  41. return;
  42. }
  43. - // Skip the query host, type (2 bytes) and class (2 bytes).
  44. char host[PACKETSZ], answer[PACKETSZ];
  45. unsigned char *p = response + sizeof(HEADER);
  46. - int status = local_dn_expand(response, response + responseLength, p, host, sizeof(host));
  47. - if (status < 0) {
  48. + int status;
  49. +
  50. + if (ntohs(header->qdcount) == 1) {
  51. + // Skip the query host, type (2 bytes) and class (2 bytes).
  52. + status = local_dn_expand(response, response + responseLength, p, host, sizeof(host));
  53. + if (status < 0) {
  54. + reply->error = QDnsLookup::InvalidReplyError;
  55. + reply->errorString = tr("Could not expand domain name");
  56. + return;
  57. + }
  58. + if ((p - response) + status + 4 >= responseLength)
  59. + header->qdcount = 0xffff; // invalid reply below
  60. + else
  61. + p += status + 4;
  62. + }
  63. + if (ntohs(header->qdcount) > 1) {
  64. reply->error = QDnsLookup::InvalidReplyError;
  65. - reply->errorString = tr("Could not expand domain name");
  66. + reply->errorString = tr("Invalid reply received");
  67. return;
  68. }
  69. - p += status + 4;
  70. // Extract results.
  71. + const int answerCount = ntohs(header->ancount);
  72. int answerIndex = 0;
  73. while ((p < response + responseLength) && (answerIndex < answerCount)) {
  74. status = local_dn_expand(response, response + responseLength, p, host, sizeof(host));
  75. @@ -249,6 +261,11 @@ void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestN
  76. const QString name = QUrl::fromAce(host);
  77. p += status;
  78. +
  79. + if ((p - response) + 10 > responseLength) {
  80. + // probably just a truncated reply, return what we have
  81. + return;
  82. + }
  83. const quint16 type = (p[0] << 8) | p[1];
  84. p += 2; // RR type
  85. p += 2; // RR class
  86. @@ -256,6 +273,8 @@ void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestN
  87. p += 4;
  88. const quint16 size = (p[0] << 8) | p[1];
  89. p += 2;
  90. + if ((p - response) + size > responseLength)
  91. + return; // truncated
  92. if (type == QDnsLookup::A) {
  93. if (size != 4) {
  94. --
  95. 2.46.0