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>
Reviewed-by: Siyuan Fu <siyuan.fu@intel.com>
\r
@param Instance The DNS instance\r
@param RxString Received buffer.\r
\r
@param Instance The DNS instance\r
@param RxString Received buffer.\r
+ @param Length Received buffer length.\r
@param Completed Flag to indicate that Dns response is valid.\r
\r
@retval EFI_SUCCESS Parse Dns Response successfully.\r
@param Completed Flag to indicate that Dns response is valid.\r
\r
@retval EFI_SUCCESS Parse Dns Response successfully.\r
ParseDnsResponse (\r
IN OUT DNS_INSTANCE *Instance,\r
IN UINT8 *RxString,\r
ParseDnsResponse (\r
IN OUT DNS_INSTANCE *Instance,\r
IN UINT8 *RxString,\r
OUT BOOLEAN *Completed\r
)\r
{\r
DNS_HEADER *DnsHeader;\r
\r
CHAR8 *QueryName;\r
OUT BOOLEAN *Completed\r
)\r
{\r
DNS_HEADER *DnsHeader;\r
\r
CHAR8 *QueryName;\r
DNS_QUERY_SECTION *QuerySection;\r
\r
CHAR8 *AnswerName;\r
DNS_QUERY_SECTION *QuerySection;\r
\r
CHAR8 *AnswerName;\r
DNS6_RESOURCE_RECORD *Dns6RR;\r
\r
EFI_STATUS Status;\r
DNS6_RESOURCE_RECORD *Dns6RR;\r
\r
EFI_STATUS Status;\r
+ UINT32 RemainingLength;\r
\r
*Completed = TRUE;\r
Status = EFI_SUCCESS;\r
\r
*Completed = TRUE;\r
Status = EFI_SUCCESS;\r
+ RemainingLength = Length;\r
+\r
+ //\r
+ // Check whether the remaining packet length is avaiable or not.\r
+ //\r
+ if (RemainingLength <= sizeof (DNS_HEADER)) {\r
+ *Completed = FALSE;\r
+ return EFI_ABORTED;\r
+ } else {\r
+ RemainingLength -= sizeof (DNS_HEADER);\r
+ }\r
DnsHeader->AuthorityNum = NTOHS (DnsHeader->AuthorityNum);\r
DnsHeader->AditionalNum = NTOHS (DnsHeader->AditionalNum);\r
\r
DnsHeader->AuthorityNum = NTOHS (DnsHeader->AuthorityNum);\r
DnsHeader->AditionalNum = NTOHS (DnsHeader->AditionalNum);\r
\r
+ //\r
+ // There is always one QuestionsNum in DNS message. The capability to handle more\r
+ // than one requires to redesign the message format. Currently, it's not supported.\r
+ //\r
+ if (DnsHeader->QuestionsNum > 1) {\r
+ *Completed = FALSE;\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
//\r
// Get Query name\r
//\r
QueryName = (CHAR8 *) (RxString + sizeof (*DnsHeader));\r
\r
//\r
// Get Query name\r
//\r
QueryName = (CHAR8 *) (RxString + sizeof (*DnsHeader));\r
\r
+ QueryNameLen = (UINT32) AsciiStrLen (QueryName) + 1;\r
+\r
+ // Check whether the remaining packet length is avaiable or not.\r
- QuerySection = (DNS_QUERY_SECTION *) (QueryName + AsciiStrLen (QueryName) + 1);\r
- QuerySection->Type = NTOHS (QuerySection->Type);\r
- QuerySection->Class = NTOHS (QuerySection->Class);\r
+ if (RemainingLength <= QueryNameLen + sizeof (DNS_QUERY_SECTION)) {\r
+ *Completed = FALSE;\r
+ return EFI_ABORTED;\r
+ } else {\r
+ RemainingLength -= (QueryNameLen + sizeof (DNS_QUERY_SECTION));\r
+ }\r
- AnswerName = (CHAR8 *) QuerySection + sizeof (*QuerySection);\r
+ QuerySection = (DNS_QUERY_SECTION *) (QueryName + QueryNameLen);\r
+ QuerySection->Type = NTOHS (QuerySection->Type);\r
+ QuerySection->Class = NTOHS (QuerySection->Class);\r
\r
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
\r
\r
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
\r
\r
Status = EFI_NOT_FOUND;\r
\r
\r
Status = EFI_NOT_FOUND;\r
\r
+ //\r
+ // Get Answer name\r
+ //\r
+ AnswerName = (CHAR8 *) QuerySection + sizeof (*QuerySection);\r
+\r
//\r
// Processing AnswerSection.\r
//\r
while (AnswerSectionNum < DnsHeader->AnswersNum) {\r
//\r
// Processing AnswerSection.\r
//\r
while (AnswerSectionNum < DnsHeader->AnswersNum) {\r
+ //\r
+ // Check whether the remaining packet length is avaiable or not.\r
+ //\r
+ if (RemainingLength <= sizeof (UINT16) + sizeof (DNS_ANSWER_SECTION)) {\r
+ *Completed = FALSE;\r
+ Status = EFI_ABORTED;\r
+ goto ON_EXIT;\r
+ } else {\r
+ RemainingLength -= (sizeof (UINT16) + sizeof (DNS_ANSWER_SECTION));\r
+ }\r
+\r
//\r
// Answer name should be PTR, else EFI_UNSUPPORTED returned.\r
//\r
//\r
// Answer name should be PTR, else EFI_UNSUPPORTED returned.\r
//\r
AnswerSection->Ttl = NTOHL (AnswerSection->Ttl);\r
AnswerSection->DataLength = NTOHS (AnswerSection->DataLength);\r
\r
AnswerSection->Ttl = NTOHL (AnswerSection->Ttl);\r
AnswerSection->DataLength = NTOHS (AnswerSection->DataLength);\r
\r
+ //\r
+ // Check whether the remaining packet length is avaiable or not.\r
+ //\r
+ if (RemainingLength < AnswerSection->DataLength) {\r
+ *Completed = FALSE;\r
+ Status = EFI_ABORTED;\r
+ goto ON_EXIT;\r
+ } else {\r
+ RemainingLength -= AnswerSection->DataLength;\r
+ }\r
+\r
//\r
// Check whether it's the GeneralLookUp querying.\r
//\r
//\r
// Check whether it's the GeneralLookUp querying.\r
//\r
DNS_INSTANCE *Instance;\r
\r
UINT8 *RcvString;\r
DNS_INSTANCE *Instance;\r
\r
UINT8 *RcvString;\r
\r
BOOLEAN Completed;\r
\r
\r
BOOLEAN Completed;\r
\r
\r
ASSERT (Packet != NULL);\r
\r
\r
ASSERT (Packet != NULL);\r
\r
- if (Packet->TotalSize <= sizeof (DNS_HEADER)) {\r
- goto ON_EXIT;\r
- }\r
+ Len = Packet->TotalSize;\r
\r
RcvString = NetbufGetByte (Packet, 0, NULL);\r
ASSERT (RcvString != NULL);\r
\r
RcvString = NetbufGetByte (Packet, 0, NULL);\r
ASSERT (RcvString != NULL);\r
//\r
// Parse Dns Response\r
//\r
//\r
// Parse Dns Response\r
//\r
- ParseDnsResponse (Instance, RcvString, &Completed);\r
+ ParseDnsResponse (Instance, RcvString, Len, &Completed);\r
\r
@param Instance The DNS instance\r
@param RxString Received buffer.\r
\r
@param Instance The DNS instance\r
@param RxString Received buffer.\r
+ @param Length Received buffer length.\r
@param Completed Flag to indicate that Dns response is valid.\r
\r
@retval EFI_SUCCESS Parse Dns Response successfully.\r
@param Completed Flag to indicate that Dns response is valid.\r
\r
@retval EFI_SUCCESS Parse Dns Response successfully.\r
ParseDnsResponse (\r
IN OUT DNS_INSTANCE *Instance,\r
IN UINT8 *RxString,\r
ParseDnsResponse (\r
IN OUT DNS_INSTANCE *Instance,\r
IN UINT8 *RxString,\r
OUT BOOLEAN *Completed\r
);\r
\r
OUT BOOLEAN *Completed\r
);\r
\r