public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: Laszlo Ersek <lersek@redhat.com>
To: edk2-devel-01 <edk2-devel@lists.01.org>
Cc: "Jaben Carsey" <jaben.carsey@intel.com>,
	"Marvin Häuser" <Marvin.Haeuser@outlook.com>,
	"Qiu Shumin" <shumin.qiu@intel.com>,
	"Ruiyu Ni" <ruiyu.ni@intel.com>
Subject: [PATCH 1/2] ShellPkg/Shell: clean up bogus member types in SPLIT_LIST
Date: Tue, 25 Apr 2017 15:57:26 +0200	[thread overview]
Message-ID: <20170425135727.4862-2-lersek@redhat.com> (raw)
In-Reply-To: <20170425135727.4862-1-lersek@redhat.com>

The "SPLIT_LIST.SplitStdOut" and "SPLIT_LIST.SplitStdIn" members currently
have type (SHELL_FILE_HANDLE *). This is wrong; SHELL_FILE_HANDLE is
already a pointer, there's no need to store a pointer to a pointer.

The error is obvious if we check where and how these members are used:

- In the RunSplitCommand() function, these members are used (populated)
  extensively; this function has to be updated in sync.

  ConvertEfiFileProtocolToShellHandle() already returns the temporary
  memory file created with CreateFileInterfaceMem() as SHELL_FILE_HANDLE,
  not as (SHELL_FILE_HANDLE *).

- In particular, the ConvertShellHandleToEfiFileProtocol() calls need to
  be dropped as well in RunSplitCommand(), since
  EFI_SHELL_PROTOCOL.SetFilePosition() and EFI_SHELL_PROTOCOL.CloseFile()
  take SHELL_FILE_HANDLE parameters, not (EFI_FILE_PROTOCOL *).

  Given that ConvertShellHandleToEfiFileProtocol() only performs a
  type-cast (it does not adjust any pointer values), *and*
  SHELL_FILE_HANDLE -- taken by EFI_SHELL_PROTOCOL member functions -- is
  actually a typedef to (VOID *) -- see more on this later --, this
  conversion error hasn't been caught by compilers.

- In the ProcessNewSplitCommandLine() function, RunSplitCommand() is
  called either initially (passing in NULL / NULL; no update needed), or
  recursively (passing in Split->SplitStdIn / Split->SplitStdOut; again no
  update is necessary beyond the RunSplitCommand() modification above).

- In the UpdateStdInStdOutStdErr() and RestoreStdInStdOutStdErr()
  functions, said structure members are compared and assigned to
  "EFI_SHELL_PARAMETERS_PROTOCOL.StdIn" and
  "EFI_SHELL_PARAMETERS_PROTOCOL.StdOut", both of which have type
  SHELL_FILE_HANDLE, *not* (SHELL_FILE_HANDLE *).

  The compiler hasn't caught this error because of the fatally flawed type
  definition of SHELL_FILE_HANDLE, namely

    typedef VOID *SHELL_FILE_HANDLE;

  Pointer-to-void silently converts to and from most other pointer types;
  among them, pointer-to-pointer-to-void. That is also why no update is
  necessary for UpdateStdInStdOutStdErr() and RestoreStdInStdOutStdErr()
  in this fix.

(

Generally speaking, using (VOID *) typedefs for opaque handles is a tragic
mistake in all of the UEFI-related specifications; this practice defeats
any type checking that compilers might help programmers with. The right
way to define an opaque handle is as follows:

  //
  // Introduce the incomplete structure type, and the derived pointer
  // type, in both the specification and the public edk2 headers. Note
  // that the derived pointer type itself is a complete type, and it can
  // be used freely by client code.
  //
  typedef struct SHELL_FILE *SHELL_FILE_HANDLE;

  //
  // Complete the structure type in the edk2 internal C source files.
  //
  struct SHELL_FILE {
    //
    // list fields
    //
  };

This way the structure size and members remain hidden from client code,
but the C compiler can nonetheless catch any invalid conversions between
incompatible XXX_HANDLE types.

)

Cc: Jaben Carsey <jaben.carsey@intel.com>
Cc: Marvin Häuser <Marvin.Haeuser@outlook.com>
Cc: Qiu Shumin <shumin.qiu@intel.com>
Cc: Ruiyu Ni <ruiyu.ni@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---
 ShellPkg/Application/Shell/Shell.h |  4 ++--
 ShellPkg/Application/Shell/Shell.c | 12 ++++++------
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/ShellPkg/Application/Shell/Shell.h b/ShellPkg/Application/Shell/Shell.h
index 25ac114da71d..ff0849446817 100644
--- a/ShellPkg/Application/Shell/Shell.h
+++ b/ShellPkg/Application/Shell/Shell.h
@@ -63,8 +63,8 @@ extern CONST CHAR16 mNoNestingFalse[];
 
 typedef struct {
   LIST_ENTRY        Link;           ///< Standard linked list handler.
-  SHELL_FILE_HANDLE *SplitStdOut;   ///< ConsoleOut for use in the split.
-  SHELL_FILE_HANDLE *SplitStdIn;    ///< ConsoleIn for use in the split.
+  SHELL_FILE_HANDLE SplitStdOut;    ///< ConsoleOut for use in the split.
+  SHELL_FILE_HANDLE SplitStdIn;     ///< ConsoleIn for use in the split.
 } SPLIT_LIST;
 
 typedef struct {
diff --git a/ShellPkg/Application/Shell/Shell.c b/ShellPkg/Application/Shell/Shell.c
index 4383298aab72..fa958170a1db 100644
--- a/ShellPkg/Application/Shell/Shell.c
+++ b/ShellPkg/Application/Shell/Shell.c
@@ -1714,8 +1714,8 @@ ShellConvertVariables (
 EFI_STATUS
 RunSplitCommand(
   IN CONST CHAR16             *CmdLine,
-  IN       SHELL_FILE_HANDLE  *StdIn,
-  IN       SHELL_FILE_HANDLE  *StdOut
+  IN       SHELL_FILE_HANDLE  StdIn,
+  IN       SHELL_FILE_HANDLE  StdOut
   )
 {
   EFI_STATUS        Status;
@@ -1724,7 +1724,7 @@ RunSplitCommand(
   UINTN             Size1;
   UINTN             Size2;
   SPLIT_LIST        *Split;
-  SHELL_FILE_HANDLE *TempFileHandle;
+  SHELL_FILE_HANDLE TempFileHandle;
   BOOLEAN           Unicode;
 
   ASSERT(StdOut == NULL);
@@ -1790,7 +1790,7 @@ RunSplitCommand(
     Split->SplitStdOut  = Split->SplitStdIn;
   }
   Split->SplitStdIn   = TempFileHandle;
-  ShellInfoObject.NewEfiShellProtocol->SetFilePosition(ConvertShellHandleToEfiFileProtocol(Split->SplitStdIn), 0);
+  ShellInfoObject.NewEfiShellProtocol->SetFilePosition (Split->SplitStdIn, 0);
 
   if (!EFI_ERROR(Status)) {
     Status = RunCommand(NextCommandLine);
@@ -1806,10 +1806,10 @@ RunSplitCommand(
   // Note that the original StdIn is now the StdOut...
   //
   if (Split->SplitStdOut != NULL) {
-    ShellInfoObject.NewEfiShellProtocol->CloseFile(ConvertShellHandleToEfiFileProtocol(Split->SplitStdOut));
+    ShellInfoObject.NewEfiShellProtocol->CloseFile (Split->SplitStdOut);
   }
   if (Split->SplitStdIn != NULL) {
-    ShellInfoObject.NewEfiShellProtocol->CloseFile(ConvertShellHandleToEfiFileProtocol(Split->SplitStdIn));
+    ShellInfoObject.NewEfiShellProtocol->CloseFile (Split->SplitStdIn);
     FreePool (Split->SplitStdIn);
   }
 
-- 
2.9.3




  reply	other threads:[~2017-04-25 13:57 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-04-25 13:57 [PATCH 0/2] ShellPkg/Shell: fix double free in pipeline processing Laszlo Ersek
2017-04-25 13:57 ` Laszlo Ersek [this message]
2017-04-25 13:57 ` [PATCH 2/2] ShellPkg/Shell: eliminate double-free in RunSplitCommand() Laszlo Ersek
2017-04-25 15:28 ` [PATCH 0/2] ShellPkg/Shell: fix double free in pipeline processing Carsey, Jaben
2017-04-26 10:17   ` Laszlo Ersek

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=20170425135727.4862-2-lersek@redhat.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