Reviewed-by: Siyuan Fu <siyuan...@intel.com>

> -----Original Message-----
> From: Wu, Jiaxin
> Sent: Tuesday, February 26, 2019 4:14 PM
> To: edk2-devel@lists.01.org
> Cc: Ye, Ting <ting...@intel.com>; Fu, Siyuan <siyuan...@intel.com>; Wang, Fan
> <fan.w...@intel.com>; Wu, Jiaxin <jiaxin...@intel.com>
> Subject: [PATCH v1] NetworkPkg/DnsDxe: Check the received packet size before
> parsing the message.
> 
> 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...@intel.com>
> Cc: Fu Siyuan <siyuan...@intel.com>
> Cc: Wang Fan <fan.w...@intel.com>
> Contributed-under: TianoCore Contribution Agreement 1.0
> Signed-off-by: Wu Jiaxin <jiaxin...@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

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to