public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Fu, Siyuan" <siyuan.fu@intel.com>
To: "Wu, Jiaxin" <jiaxin.wu@intel.com>,
	"edk2-devel@lists.01.org" <edk2-devel@lists.01.org>
Cc: "Ye, Ting" <ting.ye@intel.com>, "Wang, Fan" <fan.wang@intel.com>
Subject: Re: [PATCH v1] NetworkPkg/DnsDxe: Check the received packet size before parsing the message.
Date: Tue, 26 Feb 2019 08:24:05 +0000	[thread overview]
Message-ID: <B1FF2E9001CE9041BD10B825821D5BC58B6EEDF1@SHSMSX103.ccr.corp.intel.com> (raw)
In-Reply-To: <20190226081416.9400-1-Jiaxin.wu@intel.com>

Reviewed-by: Siyuan Fu <siyuan.fu@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.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.
> 
> 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



  reply	other threads:[~2019-02-26  8:24 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-02-26  8:14 [PATCH v1] NetworkPkg/DnsDxe: Check the received packet size before parsing the message Jiaxin Wu
2019-02-26  8:24 ` Fu, Siyuan [this message]
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=B1FF2E9001CE9041BD10B825821D5BC58B6EEDF1@SHSMSX103.ccr.corp.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