From: Jiaxin Wu <Jiaxin.wu@intel.com>
To: edk2-devel@lists.01.org
Cc: Ye Ting <ting.ye@intel.com>, Fu Siyuan <siyuan.fu@intel.com>,
Wang Fan <fan.wang@intel.com>, Wu Jiaxin <jiaxin.wu@intel.com>
Subject: [PATCH v1] NetworkPkg/DnsDxe: Check the received packet size before parsing the message.
Date: Tue, 26 Feb 2019 16:14:16 +0800 [thread overview]
Message-ID: <20190226081416.9400-1-Jiaxin.wu@intel.com> (raw)
Fix CVE-2018-12178
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=809
The DNS driver only checks the received packet size against the
minimum DNS header size in DnsOnPacketReceived(), later it accesses
the QueryName and QuerySection beyond the header scope, which might
cause the pointer within DNS driver points to an invalid entry or
modifies the memory content beyond the header scope.
This patch is to fix above problem.
Cc: Ye Ting <ting.ye@intel.com>
Cc: Fu Siyuan <siyuan.fu@intel.com>
Cc: Wang Fan <fan.wang@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Wu Jiaxin <jiaxin.wu@intel.com>
---
NetworkPkg/DnsDxe/DnsImpl.c | 77 ++++++++++++++++++++++++++++++++-----
NetworkPkg/DnsDxe/DnsImpl.h | 2 +
2 files changed, 69 insertions(+), 10 deletions(-)
diff --git a/NetworkPkg/DnsDxe/DnsImpl.c b/NetworkPkg/DnsDxe/DnsImpl.c
index 89ea755cb2..26a718987c 100644
--- a/NetworkPkg/DnsDxe/DnsImpl.c
+++ b/NetworkPkg/DnsDxe/DnsImpl.c
@@ -1112,26 +1112,29 @@ IsValidDnsResponse (
/**
Parse Dns Response.
@param Instance The DNS instance
@param RxString Received buffer.
+ @param Length Received buffer length.
@param Completed Flag to indicate that Dns response is valid.
@retval EFI_SUCCESS Parse Dns Response successfully.
@retval Others Failed to parse Dns Response.
**/
EFI_STATUS
ParseDnsResponse (
IN OUT DNS_INSTANCE *Instance,
IN UINT8 *RxString,
+ IN UINT32 Length,
OUT BOOLEAN *Completed
)
{
DNS_HEADER *DnsHeader;
CHAR8 *QueryName;
+ UINT32 QueryNameLen;
DNS_QUERY_SECTION *QuerySection;
CHAR8 *AnswerName;
DNS_ANSWER_SECTION *AnswerSection;
UINT8 *AnswerData;
@@ -1153,10 +1156,11 @@ ParseDnsResponse (
DNS_RESOURCE_RECORD *Dns4RR;
DNS6_RESOURCE_RECORD *Dns6RR;
EFI_STATUS Status;
+ UINT32 RemainingLength;
EFI_TPL OldTpl;
Item = NULL;
Dns4TokenEntry = NULL;
@@ -1176,10 +1180,21 @@ ParseDnsResponse (
Dns4RR = NULL;
Dns6RR = NULL;
*Completed = TRUE;
Status = EFI_SUCCESS;
+ RemainingLength = Length;
+
+ //
+ // Check whether the remaining packet length is avaiable or not.
+ //
+ if (RemainingLength <= sizeof (DNS_HEADER)) {
+ *Completed = FALSE;
+ return EFI_ABORTED;
+ } else {
+ RemainingLength -= sizeof (DNS_HEADER);
+ }
//
// Get header
//
DnsHeader = (DNS_HEADER *) RxString;
@@ -1189,26 +1204,42 @@ ParseDnsResponse (
DnsHeader->QuestionsNum = NTOHS (DnsHeader->QuestionsNum);
DnsHeader->AnswersNum = NTOHS (DnsHeader->AnswersNum);
DnsHeader->AuthorityNum = NTOHS (DnsHeader->AuthorityNum);
DnsHeader->AditionalNum = NTOHS (DnsHeader->AditionalNum);
+ //
+ // There is always one QuestionsNum in DNS message. The capability to handle more
+ // than one requires to redesign the message format. Currently, it's not supported.
+ //
+ if (DnsHeader->QuestionsNum > 1) {
+ *Completed = FALSE;
+ return EFI_UNSUPPORTED;
+ }
+
//
// Get Query name
//
QueryName = (CHAR8 *) (RxString + sizeof (*DnsHeader));
+ QueryNameLen = (UINT32) AsciiStrLen (QueryName) + 1;
+
//
- // Get query section
+ // Check whether the remaining packet length is avaiable or not.
//
- QuerySection = (DNS_QUERY_SECTION *) (QueryName + AsciiStrLen (QueryName) + 1);
- QuerySection->Type = NTOHS (QuerySection->Type);
- QuerySection->Class = NTOHS (QuerySection->Class);
+ if (RemainingLength <= QueryNameLen + sizeof (DNS_QUERY_SECTION)) {
+ *Completed = FALSE;
+ return EFI_ABORTED;
+ } else {
+ RemainingLength -= (QueryNameLen + sizeof (DNS_QUERY_SECTION));
+ }
//
- // Get Answer name
+ // Get query section
//
- AnswerName = (CHAR8 *) QuerySection + sizeof (*QuerySection);
+ QuerySection = (DNS_QUERY_SECTION *) (QueryName + QueryNameLen);
+ QuerySection->Type = NTOHS (QuerySection->Type);
+ QuerySection->Class = NTOHS (QuerySection->Class);
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
//
// Check DnsResponse Validity, if so, also get a valid NET_MAP_ITEM.
@@ -1339,14 +1370,30 @@ ParseDnsResponse (
}
}
Status = EFI_NOT_FOUND;
+ //
+ // Get Answer name
+ //
+ AnswerName = (CHAR8 *) QuerySection + sizeof (*QuerySection);
+
//
// Processing AnswerSection.
//
while (AnswerSectionNum < DnsHeader->AnswersNum) {
+ //
+ // Check whether the remaining packet length is avaiable or not.
+ //
+ if (RemainingLength <= sizeof (UINT16) + sizeof (DNS_ANSWER_SECTION)) {
+ *Completed = FALSE;
+ Status = EFI_ABORTED;
+ goto ON_EXIT;
+ } else {
+ RemainingLength -= (sizeof (UINT16) + sizeof (DNS_ANSWER_SECTION));
+ }
+
//
// Answer name should be PTR, else EFI_UNSUPPORTED returned.
//
if ((*(UINT8 *) AnswerName & 0xC0) != 0xC0) {
Status = EFI_UNSUPPORTED;
@@ -1360,10 +1407,21 @@ ParseDnsResponse (
AnswerSection->Type = NTOHS (AnswerSection->Type);
AnswerSection->Class = NTOHS (AnswerSection->Class);
AnswerSection->Ttl = NTOHL (AnswerSection->Ttl);
AnswerSection->DataLength = NTOHS (AnswerSection->DataLength);
+ //
+ // Check whether the remaining packet length is avaiable or not.
+ //
+ if (RemainingLength < AnswerSection->DataLength) {
+ *Completed = FALSE;
+ Status = EFI_ABORTED;
+ goto ON_EXIT;
+ } else {
+ RemainingLength -= AnswerSection->DataLength;
+ }
+
//
// Check whether it's the GeneralLookUp querying.
//
if (Instance->Service->IpVersion == IP_VERSION_4 && Dns4TokenEntry->GeneralLookUp) {
Dns4RR = Dns4TokenEntry->Token->RspData.GLookupData->RRList;
@@ -1731,10 +1789,11 @@ DnsOnPacketReceived (
)
{
DNS_INSTANCE *Instance;
UINT8 *RcvString;
+ UINT32 Len;
BOOLEAN Completed;
Instance = (DNS_INSTANCE *) Context;
NET_CHECK_SIGNATURE (Instance, DNS_INSTANCE_SIGNATURE);
@@ -1746,21 +1805,19 @@ DnsOnPacketReceived (
goto ON_EXIT;
}
ASSERT (Packet != NULL);
- if (Packet->TotalSize <= sizeof (DNS_HEADER)) {
- goto ON_EXIT;
- }
+ Len = Packet->TotalSize;
RcvString = NetbufGetByte (Packet, 0, NULL);
ASSERT (RcvString != NULL);
//
// Parse Dns Response
//
- ParseDnsResponse (Instance, RcvString, &Completed);
+ ParseDnsResponse (Instance, RcvString, Len, &Completed);
ON_EXIT:
if (Packet != NULL) {
NetbufFree (Packet);
diff --git a/NetworkPkg/DnsDxe/DnsImpl.h b/NetworkPkg/DnsDxe/DnsImpl.h
index 90dc054903..45feca2160 100644
--- a/NetworkPkg/DnsDxe/DnsImpl.h
+++ b/NetworkPkg/DnsDxe/DnsImpl.h
@@ -581,20 +581,22 @@ IsValidDnsResponse (
/**
Parse Dns Response.
@param Instance The DNS instance
@param RxString Received buffer.
+ @param Length Received buffer length.
@param Completed Flag to indicate that Dns response is valid.
@retval EFI_SUCCESS Parse Dns Response successfully.
@retval Others Failed to parse Dns Response.
**/
EFI_STATUS
ParseDnsResponse (
IN OUT DNS_INSTANCE *Instance,
IN UINT8 *RxString,
+ IN UINT32 Length,
OUT BOOLEAN *Completed
);
/**
Parse response packet.
--
2.17.1.windows.2
next reply other threads:[~2019-02-26 8:14 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-02-26 8:14 Jiaxin Wu [this message]
2019-02-26 8:24 ` [PATCH v1] NetworkPkg/DnsDxe: Check the received packet size before parsing the message Fu, Siyuan
2019-02-26 11:16 ` Laszlo Ersek
2019-02-27 3:17 ` Wu, Jiaxin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20190226081416.9400-1-Jiaxin.wu@intel.com \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox