Caller don't need to free the buffer returned from 'EfiShellGetEnv'.
So for Shell internal code if it used 'EfiShellGetEnv' to get variable the 
unfreed buffer may cause memory leak.
So this patch add a 'InternalShellGetEnv' to get environment variable to avoid 
this issue.

Cc: Jaben Carsey <jaben.car...@intel.com>
Cc: Ruiyu Ni <ruiyu...@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Qiu Shumin <shumin....@intel.com>
---
 ShellPkg/Application/Shell/Shell.c         |  41 ++++++----
 ShellPkg/Application/Shell/ShellProtocol.c | 125 +++++++++++++++++++++++++++++
 ShellPkg/Application/Shell/ShellProtocol.h |  30 +++++++
 3 files changed, 181 insertions(+), 15 deletions(-)

diff --git a/ShellPkg/Application/Shell/Shell.c 
b/ShellPkg/Application/Shell/Shell.c
index be97879..8ec4531 100644
--- a/ShellPkg/Application/Shell/Shell.c
+++ b/ShellPkg/Application/Shell/Shell.c
@@ -1436,17 +1436,20 @@ ShellConvertVariables (
   IN CONST CHAR16 *OriginalCommandLine
   )
 {
-  CONST CHAR16        *MasterEnvList;
+  CHAR16              *MasterEnvList;
+  CHAR16              *EnvListWalker;
   UINTN               NewSize;
   CHAR16              *NewCommandLine1;
   CHAR16              *NewCommandLine2;
   CHAR16              *Temp;
   UINTN               ItemSize;
   CHAR16              *ItemTemp;
+  CHAR16              *TempVar;
   SCRIPT_FILE         *CurrentScriptFile;
   ALIAS_LIST          *AliasListNode;
 
   ASSERT(OriginalCommandLine != NULL);
+  TempVar = NULL;
 
   ItemSize          = 0;
   NewSize           = StrSize(OriginalCommandLine);
@@ -1477,23 +1480,27 @@ ShellConvertVariables (
     }
   }
 
-  for (MasterEnvList = EfiShellGetEnv(NULL)
-    ;  MasterEnvList != NULL && *MasterEnvList != CHAR_NULL //&& 
*(MasterEnvList+1) != CHAR_NULL
-    ;  MasterEnvList += StrLen(MasterEnvList) + 1
+  MasterEnvList = InternalShellGetEnv(NULL);
+  ASSERT(MasterEnvList);
+  for (EnvListWalker = MasterEnvList
+    ;  EnvListWalker != NULL && *EnvListWalker != CHAR_NULL //&& 
*(MasterEnvList+1) != CHAR_NULL
+    ;  EnvListWalker += StrLen(EnvListWalker) + 1
    ){
-    if (StrSize(MasterEnvList) > ItemSize) {
-      ItemSize = StrSize(MasterEnvList);
+    if (StrSize(EnvListWalker) > ItemSize) {
+      ItemSize = StrSize(EnvListWalker);
     }
-    for (Temp = StrStr(OriginalCommandLine, MasterEnvList)
+    for (Temp = StrStr(OriginalCommandLine, EnvListWalker)
       ;  Temp != NULL
-      ;  Temp = StrStr(Temp+1, MasterEnvList)
+      ;  Temp = StrStr(Temp+1, EnvListWalker)
      ){
       //
       // we need a preceding and following % and if there is space no ^ 
preceding (if no space ignore)
       //
-      if (*(Temp-1) == L'%' && *(Temp+StrLen(MasterEnvList)) == L'%' &&
+      if (*(Temp-1) == L'%' && *(Temp+StrLen(EnvListWalker)) == L'%' &&
         ((((Temp-OriginalCommandLine)>2) && *(Temp-2) != L'^') || 
((Temp-OriginalCommandLine)<=2))) {
-        NewSize+=StrSize(EfiShellGetEnv(MasterEnvList));
+        TempVar = InternalShellGetEnv(EnvListWalker);
+        NewSize+=StrSize(TempVar);
+        SHELL_FREE_NON_NULL(TempVar);
       }
     }
   }
@@ -1508,11 +1515,12 @@ ShellConvertVariables (
     SHELL_FREE_NON_NULL(NewCommandLine1);
     SHELL_FREE_NON_NULL(NewCommandLine2);
     SHELL_FREE_NON_NULL(ItemTemp);
+    FreePool(MasterEnvList);
     return (NULL);
   }
-  for (MasterEnvList = EfiShellGetEnv(NULL)
-    ;  MasterEnvList != NULL && *MasterEnvList != CHAR_NULL
-    ;  MasterEnvList += StrLen(MasterEnvList) + 1
+  for (EnvListWalker = MasterEnvList
+    ;  EnvListWalker != NULL && *EnvListWalker != CHAR_NULL
+    ;  EnvListWalker += StrLen(EnvListWalker) + 1
    ){
     StrCpyS( ItemTemp, 
               ((ItemSize+(2*sizeof(CHAR16)))/sizeof(CHAR16)), 
@@ -1520,14 +1528,16 @@ ShellConvertVariables (
               );
     StrCatS( ItemTemp, 
               ((ItemSize+(2*sizeof(CHAR16)))/sizeof(CHAR16)), 
-              MasterEnvList
+              EnvListWalker
               );
     StrCatS( ItemTemp, 
               ((ItemSize+(2*sizeof(CHAR16)))/sizeof(CHAR16)), 
               L"%"
               );
-    ShellCopySearchAndReplace(NewCommandLine1, NewCommandLine2, NewSize, 
ItemTemp, EfiShellGetEnv(MasterEnvList), TRUE, FALSE);
+    TempVar = InternalShellGetEnv(EnvListWalker);
+    ShellCopySearchAndReplace(NewCommandLine1, NewCommandLine2, NewSize, 
ItemTemp, TempVar, TRUE, FALSE);
     StrCpyS(NewCommandLine1, NewSize/sizeof(CHAR16), NewCommandLine2);
+    SHELL_FREE_NON_NULL(TempVar);
   }
   if (CurrentScriptFile != NULL) {
     for (AliasListNode = 
(ALIAS_LIST*)GetFirstNode(&CurrentScriptFile->SubstList)
@@ -1552,6 +1562,7 @@ ShellConvertVariables (
   
   FreePool(NewCommandLine2);
   FreePool(ItemTemp);
+  FreePool(MasterEnvList);
 
   return (NewCommandLine1);
 }
diff --git a/ShellPkg/Application/Shell/ShellProtocol.c 
b/ShellPkg/Application/Shell/ShellProtocol.c
index 6d5fc1f..3f2e7c3 100644
--- a/ShellPkg/Application/Shell/ShellProtocol.c
+++ b/ShellPkg/Application/Shell/ShellProtocol.c
@@ -2721,6 +2721,131 @@ EfiShellGetEnv(
 }
 
 /**
+  Internal function to get either a single or list of environment variables.
+
+  If name is not NULL then this function returns the current value of the 
specified
+  environment variable.
+
+  If Name is NULL, then a list of all environment variable names is returned.  
Each is a
+  NULL terminated string with a double NULL terminating the list.
+
+  @param Name                   A pointer to the environment variable name.  If
+                                Name is NULL, then the function will return all
+                                of the defined shell environment variables.  In
+                                the case where multiple environment variables 
are
+                                being returned, each variable will be 
terminated by
+                                a NULL, and the list will be terminated by a 
double
+                                NULL.
+
+  @retval !=NULL                A pointer to the returned string.
+                                The returned pointer should be freed by the 
caller.
+
+  @retval NULL                  The environment variable doesn't exist or 
there are
+                                no environment variables.
+**/
+
+CHAR16 *
+EFIAPI
+InternalShellGetEnv(
+  IN CONST CHAR16 *Name
+  )
+{
+  EFI_STATUS  Status;
+  VOID        *Buffer;
+  UINTN       Size;
+  LIST_ENTRY  List;
+  ENV_VAR_LIST *Node;
+  CHAR16      *CurrentWriteLocation;
+
+  Size = 0;
+  Buffer = NULL;
+
+  if (Name == NULL) {
+    //
+    // Get all our environment variables
+    //
+    InitializeListHead(&List);
+    Status = GetEnvironmentVariableList(&List);
+    if (EFI_ERROR(Status)){
+      return (NULL);
+    }
+
+    //
+    // Build the semi-colon delimited list. (2 passes)
+    //
+    for ( Node = (ENV_VAR_LIST*)GetFirstNode(&List)
+      ; !IsNull(&List, &Node->Link)
+      ; Node = (ENV_VAR_LIST*)GetNextNode(&List, &Node->Link)
+     ){
+      ASSERT(Node->Key != NULL);
+      Size += StrSize(Node->Key);
+    }
+
+    Size += 2*sizeof(CHAR16);
+
+    Buffer = AllocateZeroPool(Size);
+    if (Buffer == NULL) {
+      if (!IsListEmpty (&List)) {
+        FreeEnvironmentVariableList(&List);
+      }
+      return (NULL);
+    }
+    CurrentWriteLocation = (CHAR16*)Buffer;
+
+    for ( Node = (ENV_VAR_LIST*)GetFirstNode(&List)
+      ; !IsNull(&List, &Node->Link)
+      ; Node = (ENV_VAR_LIST*)GetNextNode(&List, &Node->Link)
+     ){
+      ASSERT(Node->Key != NULL);
+      StrCpyS( CurrentWriteLocation, 
+                (Size)/sizeof(CHAR16) - (CurrentWriteLocation - 
((CHAR16*)Buffer)), 
+                Node->Key
+                );
+      CurrentWriteLocation += StrLen(CurrentWriteLocation) + 1;
+    }
+
+    //
+    // Free the list...
+    //
+    if (!IsListEmpty (&List)) {
+      FreeEnvironmentVariableList(&List);
+    }
+  } else {
+    //
+    // We are doing a specific environment variable
+    //
+
+    //
+    // get the size we need for this EnvVariable
+    //
+    Status = SHELL_GET_ENVIRONMENT_VARIABLE_AND_ATTRIBUTES(Name, NULL, &Size, 
Buffer);
+    if (Status == EFI_BUFFER_TOO_SMALL) {
+      //
+      // Allocate the space and recall the get function
+      //
+      Buffer = AllocateZeroPool(Size);
+      Status = SHELL_GET_ENVIRONMENT_VARIABLE_AND_ATTRIBUTES(Name, NULL, 
&Size, Buffer);
+    }
+    //
+    // we didnt get it (might not exist)
+    // free the memory if we allocated any and return NULL
+    //
+    if (EFI_ERROR(Status)) {
+      if (Buffer != NULL) {
+        FreePool(Buffer);
+      }
+      return (NULL);
+    }
+  }
+
+  //
+  // return the buffer
+  //
+  return (Buffer);
+}
+
+
+/**
   Internal variable setting function.  Allows for setting of the read only 
variables.
 
   @param Name                   Points to the NULL-terminated environment 
variable name.
diff --git a/ShellPkg/Application/Shell/ShellProtocol.h 
b/ShellPkg/Application/Shell/ShellProtocol.h
index 5a76389..a1e3aff 100644
--- a/ShellPkg/Application/Shell/ShellProtocol.h
+++ b/ShellPkg/Application/Shell/ShellProtocol.h
@@ -927,6 +927,36 @@ InernalEfiShellStartMonitor(
   );
 
 /**
+  Internal function to get either a single or list of environment variables.
+
+  If name is not NULL then this function returns the current value of the 
specified
+  environment variable.
+
+  If Name is NULL, then a list of all environment variable names is returned.  
Each is a
+  NULL terminated string with a double NULL terminating the list.
+
+  @param Name                   A pointer to the environment variable name.  If
+                                Name is NULL, then the function will return all
+                                of the defined shell environment variables.  In
+                                the case where multiple environment variables 
are
+                                being returned, each variable will be 
terminated by
+                                a NULL, and the list will be terminated by a 
double
+                                NULL.
+
+  @retval !=NULL                A pointer to the returned string.
+                                The returned pointer should be freed by the 
caller.
+
+  @retval NULL                  The environment variable doesn't exist or 
there are
+                                no environment variables.
+**/
+CHAR16 *
+EFIAPI
+InternalShellGetEnv(
+  IN CONST CHAR16 *Name
+  );
+
+
+/**
   Notification function for keystrokes.
 
   @param[in] KeyData    The key that was pressed.
-- 
1.9.5.msysgit.1

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

Reply via email to