[if gte mso 9]>

[edk2] A leak in core - LocateProtocol()

Subject: [edk2] A leak in core - LocateProtocol()

From: "Sheldon Lu" <lxd5202@gmail.com>

To: <edk2-devel@lists.sourceforge.net>

Date: 2014-03-22 04:56:24

  • 2014-03-22 04:56:24  "Sheldon Lu"   [edk2] A leak in core - LocateProtocol()

Dear all,

 

When I was looking into the implementation code for UEFI “Protocol”, I found 2 problems.

I attached an EFI program and the source and the result debug message to prove these problems.

( The program is running in 32 bit mode and it takes about 3 hours to get the result.

I test it with AMI BIOS with DEBUG_MODE is on, so you may need to do a little modify before you can run it on your platform. )

 

The 2 problems are about LocateProtocol(), so I put its prototype here:

Prototype

typedef

EFI_STATUS LocateProtocol (

IN EFI_GUID *Protocol,

IN VOID *Registration OPTIONAL,

OUT VOID **Interface

);

 

Issue:

======================================================================================================

1.    It cannot locate a protocol successfully by one Registration for 2 times. In the 2nd time you locate the protocol by Registration, it returns EFI_NOT_FOUND.
Well, as the UEFI spec not describe this function in detail, I can
t say this is a bug, but I think it comes to be some kind of useless for this reason.

( this problem is caused by the code in red )

EFI_STATUS

EFIAPI

CoreLocateProtocol (

  IN  EFI_GUID  *Protocol,

  IN  VOID      *Registration OPTIONAL,

  OUT VOID      **Interface

  )

{

  ……

  if (Handle == NULL) {

    Status = EFI_NOT_FOUND;

  } else if (Registration != NULL) {

    //

    // If this is a search by register notify and a handle was

    // returned, update the register notification position

    //

    ProtNotify = Registration;

    ProtNotify->Position = ProtNotify->Position->ForwardLink;

  }

……

}

 

IHANDLE *

CoreGetNextLocateByRegisterNotify (

  IN OUT LOCATE_POSITION    *Position,

  OUT VOID                  **Interface

  )

{

  IHANDLE             *Handle;

  PROTOCOL_NOTIFY     *ProtNotify;

  PROTOCOL_INTERFACE  *Prot;

  LIST_ENTRY          *Link;

 

  Handle      = NULL;

  *Interface  = NULL;

  ProtNotify = Position->SearchKey;

 

  //

  // If this is the first request, get the next handle

  //

  if (ProtNotify != NULL) {

    ASSERT(ProtNotify->Signature == PROTOCOL_NOTIFY_SIGNATURE);

    Position->SearchKey = NULL;

 

    //

    // If not at the end of the list, get the next handle

    //

   Link = ProtNotify->Position->ForwardLink;

    if (Link != &ProtNotify->Protocol->Protocols) {

      Prot = CR (Link, PROTOCOL_INTERFACE, ByProtocol, PROTOCOL_INTERFACE_SIGNATURE);

      Handle = Prot->Handle;

      *Interface = Prot->Interface;

    }

  }

 

  return Handle;

}

 

 

======================================================================================================

2.    There’re 2 “counters” in handle database:
one is kept in each handle : IHANDLE.LocateRequest, it records current mEfiLocateHandleRequest value when LocateProtocol() succeeds.
the other is a global varibale : mEfiLocateHandleRequest, it increases in every LocateProtocol().

The problem is :

When mEfiLocateHandleRequest is equal to IHANDLE.LocateRequest - 1 , it will fail to locate any protocol on IHANDLE next time.

   For example,

(1) Assume both IHANDLE.LocateRequest and mEfiLocateHandleRequest is 0, and there is a protocol “A” on this handle.

(2) try to locate a “non-exist” protocol,the mEfiLocateHandleRequest will increase to 1 and IHANDLE.LocateRequest will still be 0.

(3) Repeat to locate the “non-exist” protocol, again and again, until mEfiLocateHandleRequest reaches 0xFFFFFFFF.

(4) Now, locate the “A” protocol, mEfiLocateHandleRequest will reach 0 (in 32bit mode) and equal to IHANDLE.LocateRequest.
The LocateProtocol() will return EFI_NOT_FOUND.

 

( this problem is caused by the code in red )

EFI_STATUS

EFIAPI

CoreLocateProtocol (

  IN  EFI_GUID  *Protocol,

  IN  VOID      *Registration OPTIONAL,

  OUT VOID      **Interface

  )

{

  ……

  mEfiLocateHandleRequest += 1;

  ……

}

IHANDLE *

CoreGetNextLocateByProtocol (

  IN OUT LOCATE_POSITION    *Position,

  OUT VOID                  **Interface

  )

{

……

  for (; ;) {

    ……

    //

    // If this handle has not been returned this request, then

    // return it now

    //

    if (Handle->LocateRequest != mEfiLocateHandleRequest) {

      Handle->LocateRequest = mEfiLocateHandleRequest;

      break;

    }

  }

 

  return Handle;

}

 

I would like to hear your opinions.

Really appreciate it.

 

Thank you & B.R.

Sheldon