public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [PATCH 00/10] patches for some warnings raised by "RH covscan"
@ 2019-04-12 23:31 Laszlo Ersek
  2019-04-12 23:31 ` [PATCH 01/10] MdePkg/PiFirmwareFile: express IS_SECTION2 in terms of SECTION_SIZE Laszlo Ersek
                   ` (11 more replies)
  0 siblings, 12 replies; 52+ messages in thread
From: Laszlo Ersek @ 2019-04-12 23:31 UTC (permalink / raw)
  To: edk2-devel-groups-io
  Cc: Anthony Perard, Ard Biesheuvel, Bob Feng, Jordan Justen,
	Julien Grall, Liming Gao, Michael D Kinney, Yonghong Zhu

Bugzilla: https://bugzilla.tianocore.org/show_bug.cgi?id=1710
Repo:     https://github.com/lersek/edk2.git
Branch:   covscan_bz_1710

"covscan" is an internal service at Red Hat that lets associates run
static analysis tools on Fedora/RHEL packages. It drives a number of
static analyzers.

While covscan's existence is not "secret" (if you google it, you get a
bunch of hits in the Red Hat Bugzilla), I can *not* use or offer covscan
as a general upstream tool; for that the TianoCore community will have
to build its own service / environment.

Anyway, "covscan" happened to drop a bunch of reports on me for...
"reasons", and so I turned a short 10 hour workday into yet anoher
normal 15 hour workday (stealing some free time whence there was none)
in order to do something, up-stream, about the warnings that affected
OvmfPkg. No claim is made about the completeness of the scan's coverage.

Some of the patches seek to suppress warnings, some strive to remedy
valid-looking issues. We should not spend much time on this series.

Cc: Anthony Perard <anthony.perard@citrix.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Bob Feng <bob.c.feng@intel.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Julien Grall <julien.grall@arm.com>
Cc: Liming Gao <liming.gao@intel.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Yonghong Zhu <yonghong.zhu@intel.com>

Thanks
Laszlo

Laszlo Ersek (10):
  MdePkg/PiFirmwareFile: express IS_SECTION2 in terms of SECTION_SIZE
  MdePkg/PiFirmwareFile: fix undefined behavior in SECTION_SIZE
  BaseTools/PiFirmwareFile: fix undefined behavior in SECTION_SIZE
  MdePkg/PiFirmwareFile: fix undefined behavior in FFS_FILE_SIZE
  OvmfPkg/Sec: fix out-of-bounds reads
  OvmfPkg/QemuVideoDxe: avoid arithmetic on null pointer
  OvmfPkg/AcpiPlatformDxe: suppress invalid "deref of undef pointer"
    warning
  OvmfPkg: suppress "Value stored to ... is never read" analyzer
    warnings
  OvmfPkg/AcpiPlatformDxe: catch theoretical nullptr deref in Xen code
  OvmfPkg/BasePciCapLib: suppress invalid "nullptr deref" warning

 BaseTools/Source/C/Include/Common/PiFirmwareFile.h            |  7 +++++-
 MdePkg/Include/Pi/PiFirmwareFile.h                            | 26 ++++++++++++++++----
 OvmfPkg/AcpiPlatformDxe/AcpiPlatform.c                        |  7 ++++++
 OvmfPkg/AcpiPlatformDxe/Xen.c                                 | 14 ++++++++++-
 OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c                 |  7 ++++++
 OvmfPkg/Library/PlatformBootManagerLib/QemuKernel.c           |  5 ++++
 OvmfPkg/Library/SerializeVariablesLib/SerializeVariablesLib.c |  4 +++
 OvmfPkg/Library/VirtioLib/VirtioLib.c                         |  5 ++++
 OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c       |  5 ++++
 OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockServiceDxe.c    |  5 ++++
 OvmfPkg/QemuVideoDxe/VbeShim.c                                |  2 +-
 OvmfPkg/SataControllerDxe/SataController.c                    |  5 ++++
 OvmfPkg/Sec/SecMain.c                                         |  6 ++---
 OvmfPkg/VirtioGpuDxe/Gop.c                                    |  6 +++++
 OvmfPkg/VirtioNetDxe/SnpReceive.c                             |  5 ++++
 15 files changed, 98 insertions(+), 11 deletions(-)

-- 
2.19.1.3.g30247aa5d201


^ permalink raw reply	[flat|nested] 52+ messages in thread

* [PATCH 01/10] MdePkg/PiFirmwareFile: express IS_SECTION2 in terms of SECTION_SIZE
  2019-04-12 23:31 [PATCH 00/10] patches for some warnings raised by "RH covscan" Laszlo Ersek
@ 2019-04-12 23:31 ` Laszlo Ersek
  2019-04-15 17:01   ` [edk2-devel] " Philippe Mathieu-Daudé
  2019-04-12 23:31 ` [PATCH 02/10] MdePkg/PiFirmwareFile: fix undefined behavior in SECTION_SIZE Laszlo Ersek
                   ` (10 subsequent siblings)
  11 siblings, 1 reply; 52+ messages in thread
From: Laszlo Ersek @ 2019-04-12 23:31 UTC (permalink / raw)
  To: edk2-devel-groups-io; +Cc: Liming Gao, Michael D Kinney

The IS_SECTION2() function-like macro duplicates the SECTION_SIZE()
calculation, just to compare the computed size against 0xFFFFFF. Invoke
SECTION_SIZE() instead; only preserve the comparison.

Cc: Liming Gao <liming.gao@intel.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Bugzilla: https://bugzilla.tianocore.org/show_bug.cgi?id=1710
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---
 MdePkg/Include/Pi/PiFirmwareFile.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/MdePkg/Include/Pi/PiFirmwareFile.h b/MdePkg/Include/Pi/PiFirmwareFile.h
index 56efabcba3ec..a9f3bcc4eb8e 100644
--- a/MdePkg/Include/Pi/PiFirmwareFile.h
+++ b/MdePkg/Include/Pi/PiFirmwareFile.h
@@ -475,21 +475,21 @@ typedef struct {
   ///
   /// A UINT16 that represents a particular build. Subsequent builds have monotonically
   /// increasing build numbers relative to earlier builds.
   ///
   UINT16                        BuildNumber;
   CHAR16                        VersionString[1];
 } EFI_VERSION_SECTION2;
 
-#define IS_SECTION2(SectionHeaderPtr) \
-    ((UINT32) (*((UINT32 *) ((EFI_COMMON_SECTION_HEADER *) (UINTN) SectionHeaderPtr)->Size) & 0x00ffffff) == 0x00ffffff)
-
 #define SECTION_SIZE(SectionHeaderPtr) \
     ((UINT32) (*((UINT32 *) ((EFI_COMMON_SECTION_HEADER *) (UINTN) SectionHeaderPtr)->Size) & 0x00ffffff))
 
+#define IS_SECTION2(SectionHeaderPtr) \
+    (SECTION_SIZE (SectionHeaderPtr) == 0x00ffffff)
+
 #define SECTION2_SIZE(SectionHeaderPtr) \
     (((EFI_COMMON_SECTION_HEADER2 *) (UINTN) SectionHeaderPtr)->ExtendedSize)
 
 #pragma pack()
 
 #endif
 
-- 
2.19.1.3.g30247aa5d201



^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH 02/10] MdePkg/PiFirmwareFile: fix undefined behavior in SECTION_SIZE
  2019-04-12 23:31 [PATCH 00/10] patches for some warnings raised by "RH covscan" Laszlo Ersek
  2019-04-12 23:31 ` [PATCH 01/10] MdePkg/PiFirmwareFile: express IS_SECTION2 in terms of SECTION_SIZE Laszlo Ersek
@ 2019-04-12 23:31 ` Laszlo Ersek
  2019-04-14  7:19   ` [edk2-devel] " Jordan Justen
  2019-04-12 23:31 ` [PATCH 03/10] BaseTools/PiFirmwareFile: " Laszlo Ersek
                   ` (9 subsequent siblings)
  11 siblings, 1 reply; 52+ messages in thread
From: Laszlo Ersek @ 2019-04-12 23:31 UTC (permalink / raw)
  To: edk2-devel-groups-io; +Cc: Liming Gao, Michael D Kinney

RH covscan justifiedly reports that accessing
"EFI_COMMON_SECTION_HEADER.Size", which is of type UINT8[3], through a
(UINT32*), is undefined behavior:

> Error: OVERRUN (CWE-119):
> edk2-89910a39dcfd/OvmfPkg/Sec/SecMain.c:178: overrun-local: Overrunning
> array of 3 bytes at byte offset 3 by dereferencing pointer
> "(UINT32 *)((EFI_COMMON_SECTION_HEADER *)(UINTN)Section)->Size".
> #  176|       Section = (EFI_COMMON_SECTION_HEADER*)(UINTN) CurrentAddress;
> #  177|
> #  178|->     Size = SECTION_SIZE (Section);
> #  179|       if (Size < sizeof (*Section)) {
> #  180|         return EFI_VOLUME_CORRUPTED;

Fix this by introducing EFI_COMMON_SECTION_HEADER_UNION, and expressing
SECTION_SIZE() in terms of "EFI_COMMON_SECTION_HEADER_UNION.Uint32".

Cc: Liming Gao <liming.gao@intel.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Bugzilla: https://bugzilla.tianocore.org/show_bug.cgi?id=1710
Issue: scan-1007.txt
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---
 MdePkg/Include/Pi/PiFirmwareFile.h | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/MdePkg/Include/Pi/PiFirmwareFile.h b/MdePkg/Include/Pi/PiFirmwareFile.h
index a9f3bcc4eb8e..4fce8298d1c0 100644
--- a/MdePkg/Include/Pi/PiFirmwareFile.h
+++ b/MdePkg/Include/Pi/PiFirmwareFile.h
@@ -229,16 +229,24 @@ typedef struct {
   ///
   UINT8             Size[3];
   EFI_SECTION_TYPE  Type;
   ///
   /// Declares the section type.
   ///
 } EFI_COMMON_SECTION_HEADER;
 
+///
+/// Union that permits accessing EFI_COMMON_SECTION_HEADER as a UINT32 object.
+///
+typedef union {
+  EFI_COMMON_SECTION_HEADER Hdr;
+  UINT32                    Uint32;
+} EFI_COMMON_SECTION_HEADER_UNION;
+
 typedef struct {
   ///
   /// A 24-bit unsigned integer that contains the total size of the section in bytes,
   /// including the EFI_COMMON_SECTION_HEADER.
   ///
   UINT8             Size[3];
 
   EFI_SECTION_TYPE  Type;
@@ -476,17 +484,17 @@ typedef struct {
   /// A UINT16 that represents a particular build. Subsequent builds have monotonically
   /// increasing build numbers relative to earlier builds.
   ///
   UINT16                        BuildNumber;
   CHAR16                        VersionString[1];
 } EFI_VERSION_SECTION2;
 
 #define SECTION_SIZE(SectionHeaderPtr) \
-    ((UINT32) (*((UINT32 *) ((EFI_COMMON_SECTION_HEADER *) (UINTN) SectionHeaderPtr)->Size) & 0x00ffffff))
+    (((EFI_COMMON_SECTION_HEADER_UNION *) (UINTN) (SectionHeaderPtr))->Uint32 & 0x00ffffff)
 
 #define IS_SECTION2(SectionHeaderPtr) \
     (SECTION_SIZE (SectionHeaderPtr) == 0x00ffffff)
 
 #define SECTION2_SIZE(SectionHeaderPtr) \
     (((EFI_COMMON_SECTION_HEADER2 *) (UINTN) SectionHeaderPtr)->ExtendedSize)
 
 #pragma pack()
-- 
2.19.1.3.g30247aa5d201



^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH 03/10] BaseTools/PiFirmwareFile: fix undefined behavior in SECTION_SIZE
  2019-04-12 23:31 [PATCH 00/10] patches for some warnings raised by "RH covscan" Laszlo Ersek
  2019-04-12 23:31 ` [PATCH 01/10] MdePkg/PiFirmwareFile: express IS_SECTION2 in terms of SECTION_SIZE Laszlo Ersek
  2019-04-12 23:31 ` [PATCH 02/10] MdePkg/PiFirmwareFile: fix undefined behavior in SECTION_SIZE Laszlo Ersek
@ 2019-04-12 23:31 ` Laszlo Ersek
  2019-04-12 23:31 ` [PATCH 04/10] MdePkg/PiFirmwareFile: fix undefined behavior in FFS_FILE_SIZE Laszlo Ersek
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 52+ messages in thread
From: Laszlo Ersek @ 2019-04-12 23:31 UTC (permalink / raw)
  To: edk2-devel-groups-io; +Cc: Bob Feng, Liming Gao, Yonghong Zhu

Sync SECTION_SIZE() and EFI_COMMON_SECTION_HEADER_UNION from MdePkg to
BaseTools, from an earlier patch in this series.

Cc: Bob Feng <bob.c.feng@intel.com>
Cc: Liming Gao <liming.gao@intel.com>
Cc: Yonghong Zhu <yonghong.zhu@intel.com>
Bugzilla: https://bugzilla.tianocore.org/show_bug.cgi?id=1710
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---
 BaseTools/Source/C/Include/Common/PiFirmwareFile.h | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/BaseTools/Source/C/Include/Common/PiFirmwareFile.h b/BaseTools/Source/C/Include/Common/PiFirmwareFile.h
index 5bc871df4855..0ce89e1074a7 100644
--- a/BaseTools/Source/C/Include/Common/PiFirmwareFile.h
+++ b/BaseTools/Source/C/Include/Common/PiFirmwareFile.h
@@ -144,16 +144,21 @@ typedef UINT8 EFI_SECTION_TYPE;
 #define EFI_SECTION_PEI_DEPEX             0x1B
 #define EFI_SECTION_SMM_DEPEX             0x1C
 
 typedef struct {
   UINT8             Size[3];
   EFI_SECTION_TYPE  Type;
 } EFI_COMMON_SECTION_HEADER;
 
+typedef union {
+  EFI_COMMON_SECTION_HEADER Hdr;
+  UINT32                    Uint32;
+} EFI_COMMON_SECTION_HEADER_UNION;
+
 typedef struct {
   UINT8             Size[3];
   EFI_SECTION_TYPE  Type;
   UINT32            ExtendedSize;
 } EFI_COMMON_SECTION_HEADER2;
 
 #define MAX_SECTION_SIZE        0x1000000
 
@@ -296,17 +301,17 @@ typedef struct {
 
 typedef struct {
   EFI_COMMON_SECTION_HEADER2  CommonHeader;
   UINT16                      BuildNumber;
   CHAR16                      VersionString[1];
 } EFI_VERSION_SECTION2;
 
 #define SECTION_SIZE(SectionHeaderPtr) \
-    ((UINT32) (*((UINT32 *) ((EFI_COMMON_SECTION_HEADER *) SectionHeaderPtr)->Size) & 0x00ffffff))
+    (((EFI_COMMON_SECTION_HEADER_UNION *) (SectionHeaderPtr))->Uint32 & 0x00ffffff)
 
 #pragma pack()
 
 typedef union {
   EFI_COMMON_SECTION_HEADER         *CommonHeader;
   EFI_COMPRESSION_SECTION           *CompressionSection;
   EFI_GUID_DEFINED_SECTION          *GuidDefinedSection;
   EFI_PE32_SECTION                  *Pe32Section;
-- 
2.19.1.3.g30247aa5d201



^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH 04/10] MdePkg/PiFirmwareFile: fix undefined behavior in FFS_FILE_SIZE
  2019-04-12 23:31 [PATCH 00/10] patches for some warnings raised by "RH covscan" Laszlo Ersek
                   ` (2 preceding siblings ...)
  2019-04-12 23:31 ` [PATCH 03/10] BaseTools/PiFirmwareFile: " Laszlo Ersek
@ 2019-04-12 23:31 ` Laszlo Ersek
  2019-04-15 17:23   ` [edk2-devel] " Philippe Mathieu-Daudé
  2019-04-17 17:52   ` Michael D Kinney
  2019-04-12 23:31 ` [PATCH 05/10] OvmfPkg/Sec: fix out-of-bounds reads Laszlo Ersek
                   ` (7 subsequent siblings)
  11 siblings, 2 replies; 52+ messages in thread
From: Laszlo Ersek @ 2019-04-12 23:31 UTC (permalink / raw)
  To: edk2-devel-groups-io; +Cc: Liming Gao, Michael D Kinney

Accessing "EFI_FFS_FILE_HEADER.Size", which is of type UINT8[3], through a
(UINT32*), is undefined behavior. Fix it by accessing the array elements
individually.

(We can't use a union here, unfortunately, as easily as with
"EFI_COMMON_SECTION_HEADER", given the fields in "EFI_FFS_FILE_HEADER".)

Cc: Liming Gao <liming.gao@intel.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Bugzilla: https://bugzilla.tianocore.org/show_bug.cgi?id=1710
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---
 MdePkg/Include/Pi/PiFirmwareFile.h | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/MdePkg/Include/Pi/PiFirmwareFile.h b/MdePkg/Include/Pi/PiFirmwareFile.h
index 4fce8298d1c0..0668f3fa9af4 100644
--- a/MdePkg/Include/Pi/PiFirmwareFile.h
+++ b/MdePkg/Include/Pi/PiFirmwareFile.h
@@ -174,18 +174,26 @@ typedef struct {
   /// If FFS_ATTRIB_LARGE_FILE is not set then EFI_FFS_FILE_HEADER is used.
   ///
   UINT64                    ExtendedSize;
 } EFI_FFS_FILE_HEADER2;
 
 #define IS_FFS_FILE2(FfsFileHeaderPtr) \
     (((((EFI_FFS_FILE_HEADER *) (UINTN) FfsFileHeaderPtr)->Attributes) & FFS_ATTRIB_LARGE_FILE) == FFS_ATTRIB_LARGE_FILE)
 
+#define FFS_FILE_SIZE_ARRAY(FfsFileHeaderPtr) \
+    (((EFI_FFS_FILE_HEADER *) (UINTN) (FfsFileHeaderPtr))->Size)
+
+#define FFS_FILE_SIZE_ELEMENT(FfsFileHeaderPtr, Index) \
+    ((UINT32) FFS_FILE_SIZE_ARRAY (FfsFileHeaderPtr)[(Index)])
+
 #define FFS_FILE_SIZE(FfsFileHeaderPtr) \
-    ((UINT32) (*((UINT32 *) ((EFI_FFS_FILE_HEADER *) (UINTN) FfsFileHeaderPtr)->Size) & 0x00ffffff))
+    ((FFS_FILE_SIZE_ELEMENT ((FfsFileHeaderPtr), 0) <<  0) | \
+     (FFS_FILE_SIZE_ELEMENT ((FfsFileHeaderPtr), 1) <<  8) | \
+     (FFS_FILE_SIZE_ELEMENT ((FfsFileHeaderPtr), 2) << 16))
 
 #define FFS_FILE2_SIZE(FfsFileHeaderPtr) \
     ((UINT32) (((EFI_FFS_FILE_HEADER2 *) (UINTN) FfsFileHeaderPtr)->ExtendedSize))
 
 typedef UINT8 EFI_SECTION_TYPE;
 
 ///
 /// Pseudo type. It is used as a wild card when retrieving sections.
-- 
2.19.1.3.g30247aa5d201



^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH 05/10] OvmfPkg/Sec: fix out-of-bounds reads
  2019-04-12 23:31 [PATCH 00/10] patches for some warnings raised by "RH covscan" Laszlo Ersek
                   ` (3 preceding siblings ...)
  2019-04-12 23:31 ` [PATCH 04/10] MdePkg/PiFirmwareFile: fix undefined behavior in FFS_FILE_SIZE Laszlo Ersek
@ 2019-04-12 23:31 ` Laszlo Ersek
  2019-04-15 17:24   ` [edk2-devel] " Philippe Mathieu-Daudé
  2019-04-12 23:31 ` [PATCH 06/10] OvmfPkg/QemuVideoDxe: avoid arithmetic on null pointer Laszlo Ersek
                   ` (6 subsequent siblings)
  11 siblings, 1 reply; 52+ messages in thread
From: Laszlo Ersek @ 2019-04-12 23:31 UTC (permalink / raw)
  To: edk2-devel-groups-io; +Cc: Ard Biesheuvel, Jordan Justen

RH covscan justifiedly reports that accessing "EFI_FFS_FILE_HEADER.Size"
and "EFI_COMMON_SECTION_HEADER.Size", which both are of type UINT8[3],
through (UINT32*), is undefined behavior:

> Error: OVERRUN (CWE-119):
> edk2-89910a39dcfd/OvmfPkg/Sec/SecMain.c:283: overrun-local: Overrunning
> array of 3 bytes at byte offset 3 by dereferencing pointer
> "(UINT32 *)File->Size".
> #  281|
> #  282|       File = (EFI_FFS_FILE_HEADER*)(UINTN) CurrentAddress;
> #  283|->     Size = *(UINT32*) File->Size & 0xffffff;
> #  284|       if (Size < (sizeof (*File) + sizeof (EFI_COMMON_SECTION_HEADER))) {
> #  285|         return EFI_VOLUME_CORRUPTED;
>
> Error: OVERRUN (CWE-119):
> edk2-89910a39dcfd/OvmfPkg/Sec/SecMain.c:614: overrun-local: Overrunning
> array of 3 bytes at byte offset 3 by dereferencing pointer
> "(UINT32 *)File->Size".
> #  612|
> #  613|       File = (EFI_FFS_FILE_HEADER*)(UINTN) CurrentAddress;
> #  614|->     Size = *(UINT32*) File->Size & 0xffffff;
> #  615|       if (Size < sizeof (*File)) {
> #  616|         return EFI_NOT_FOUND;
>
> Error: OVERRUN (CWE-119):
> edk2-89910a39dcfd/OvmfPkg/Sec/SecMain.c:639: overrun-local: Overrunning
> array of 3 bytes at byte offset 3 by dereferencing pointer
> "(UINT32 *)Section->Size".
> #  637|         Section = (EFI_COMMON_SECTION_HEADER*)(UINTN) CurrentAddress;
> #  638|
> #  639|->       Size = *(UINT32*) Section->Size & 0xffffff;
> #  640|         if (Size < sizeof (*Section)) {
> #  641|           return EFI_NOT_FOUND;

Fix these by invoking the FFS_FILE_SIZE() and SECTION_SIZE() macros, which
by now have been fixed too.

Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Bugzilla: https://bugzilla.tianocore.org/show_bug.cgi?id=1710
Issue: scan-1008.txt
Issue: scan-1009.txt
Issue: scan-1010.txt
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---
 OvmfPkg/Sec/SecMain.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/OvmfPkg/Sec/SecMain.c b/OvmfPkg/Sec/SecMain.c
index 18a89c649fd4..3914355cd17b 100644
--- a/OvmfPkg/Sec/SecMain.c
+++ b/OvmfPkg/Sec/SecMain.c
@@ -269,17 +269,17 @@ FindFfsFileAndSection (
   for (EndOfFile = CurrentAddress + Fv->HeaderLength; ; ) {
 
     CurrentAddress = (EndOfFile + 7) & ~(7ULL);
     if (CurrentAddress > EndOfFirmwareVolume) {
       return EFI_VOLUME_CORRUPTED;
     }
 
     File = (EFI_FFS_FILE_HEADER*)(UINTN) CurrentAddress;
-    Size = *(UINT32*) File->Size & 0xffffff;
+    Size = FFS_FILE_SIZE (File);
     if (Size < (sizeof (*File) + sizeof (EFI_COMMON_SECTION_HEADER))) {
       return EFI_VOLUME_CORRUPTED;
     }
 
     EndOfFile = CurrentAddress + Size;
     if (EndOfFile > EndOfFirmwareVolume) {
       return EFI_VOLUME_CORRUPTED;
     }
@@ -600,17 +600,17 @@ FindImageBase (
   for (EndOfFile = CurrentAddress + BootFirmwareVolumePtr->HeaderLength; ; ) {
 
     CurrentAddress = (EndOfFile + 7) & 0xfffffffffffffff8ULL;
     if (CurrentAddress > EndOfFirmwareVolume) {
       return EFI_NOT_FOUND;
     }
 
     File = (EFI_FFS_FILE_HEADER*)(UINTN) CurrentAddress;
-    Size = *(UINT32*) File->Size & 0xffffff;
+    Size = FFS_FILE_SIZE (File);
     if (Size < sizeof (*File)) {
       return EFI_NOT_FOUND;
     }
 
     EndOfFile = CurrentAddress + Size;
     if (EndOfFile > EndOfFirmwareVolume) {
       return EFI_NOT_FOUND;
     }
@@ -625,17 +625,17 @@ FindImageBase (
     //
     // Loop through the FFS file sections within the FFS file
     //
     EndOfSection = (EFI_PHYSICAL_ADDRESS)(UINTN) (File + 1);
     for (;;) {
       CurrentAddress = (EndOfSection + 3) & 0xfffffffffffffffcULL;
       Section = (EFI_COMMON_SECTION_HEADER*)(UINTN) CurrentAddress;
 
-      Size = *(UINT32*) Section->Size & 0xffffff;
+      Size = SECTION_SIZE (Section);
       if (Size < sizeof (*Section)) {
         return EFI_NOT_FOUND;
       }
 
       EndOfSection = CurrentAddress + Size;
       if (EndOfSection > EndOfFile) {
         return EFI_NOT_FOUND;
       }
-- 
2.19.1.3.g30247aa5d201



^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH 06/10] OvmfPkg/QemuVideoDxe: avoid arithmetic on null pointer
  2019-04-12 23:31 [PATCH 00/10] patches for some warnings raised by "RH covscan" Laszlo Ersek
                   ` (4 preceding siblings ...)
  2019-04-12 23:31 ` [PATCH 05/10] OvmfPkg/Sec: fix out-of-bounds reads Laszlo Ersek
@ 2019-04-12 23:31 ` Laszlo Ersek
  2019-04-12 23:31 ` [PATCH 07/10] OvmfPkg/AcpiPlatformDxe: suppress invalid "deref of undef pointer" warning Laszlo Ersek
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 52+ messages in thread
From: Laszlo Ersek @ 2019-04-12 23:31 UTC (permalink / raw)
  To: edk2-devel-groups-io; +Cc: Ard Biesheuvel, Jordan Justen

The real mode interrupt vector table, which we modify for the sake of
Windows 7, starts at address 0, which happens to be the representation of
null pointers on all edk2 architectures. A null pointer may never undergo
pointer arithmetic, and RH covscan justifiedly reports:

> Error: CPPCHECK_WARNING (CWE-682):
> edk2-89910a39dcfd/OvmfPkg/QemuVideoDxe/VbeShim.c:105:
> error[nullPointerArithmetic]: Pointer addition with NULL pointer.
> #  103|     //
> #  104|     Segment0Pages = 1;
> #  105|->   Int0x10       = (IVT_ENTRY *)(UINTN)Segment0 + 0x10;
> #  106|     Segment0AllocationStatus = gBS->AllocatePages (
> #  107|                                       AllocateAddress,

Fix this by calculating the EFI_PHYSICAL_ADDRESS of IVT entry 0x10 first,
and by casting the address to the right type second.

Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Bugzilla: https://bugzilla.tianocore.org/show_bug.cgi?id=1710
Issue: scan-1002.txt
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---
 OvmfPkg/QemuVideoDxe/VbeShim.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/OvmfPkg/QemuVideoDxe/VbeShim.c b/OvmfPkg/QemuVideoDxe/VbeShim.c
index 69081f09e630..c23dc984d453 100644
--- a/OvmfPkg/QemuVideoDxe/VbeShim.c
+++ b/OvmfPkg/QemuVideoDxe/VbeShim.c
@@ -91,17 +91,17 @@ InstallVbeShim (
   // Attempt to cover the real mode IVT with an allocation. This is a UEFI
   // driver, hence the arch protocols have been installed previously. Among
   // those, the CPU arch protocol has configured the IDT, so we can overwrite
   // the IVT used in real mode.
   //
   // The allocation request may fail, eg. if LegacyBiosDxe has already run.
   //
   Segment0Pages = 1;
-  Int0x10       = (IVT_ENTRY *)(UINTN)Segment0 + 0x10;
+  Int0x10       = (IVT_ENTRY *)(UINTN)(Segment0 + 0x10 * sizeof (IVT_ENTRY));
   Segment0AllocationStatus = gBS->AllocatePages (
                                     AllocateAddress,
                                     EfiBootServicesCode,
                                     Segment0Pages,
                                     &Segment0
                                     );
 
   if (EFI_ERROR (Segment0AllocationStatus)) {
-- 
2.19.1.3.g30247aa5d201



^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH 07/10] OvmfPkg/AcpiPlatformDxe: suppress invalid "deref of undef pointer" warning
  2019-04-12 23:31 [PATCH 00/10] patches for some warnings raised by "RH covscan" Laszlo Ersek
                   ` (5 preceding siblings ...)
  2019-04-12 23:31 ` [PATCH 06/10] OvmfPkg/QemuVideoDxe: avoid arithmetic on null pointer Laszlo Ersek
@ 2019-04-12 23:31 ` Laszlo Ersek
  2019-04-15 17:26   ` [edk2-devel] " Philippe Mathieu-Daudé
  2019-04-12 23:31 ` [PATCH 08/10] OvmfPkg: suppress "Value stored to ... is never read" analyzer warnings Laszlo Ersek
                   ` (4 subsequent siblings)
  11 siblings, 1 reply; 52+ messages in thread
From: Laszlo Ersek @ 2019-04-12 23:31 UTC (permalink / raw)
  To: edk2-devel-groups-io; +Cc: Ard Biesheuvel, Jordan Justen

RH covscan emits the following false positive:

> Error: CLANG_WARNING:
> edk2-89910a39dcfd/OvmfPkg/AcpiPlatformDxe/AcpiPlatform.c:182:14:
> warning: Dereference of undefined pointer value
> #    Status = FwVol->ReadSection (
> #             ^~~~~~~~~~~~~~~~~~
> edk2-89910a39dcfd/OvmfPkg/AcpiPlatformDxe/AcpiPlatform.c:164:7: note:
> Assuming the condition is false
> #  if (QemuDetected ()) {
> #      ^~~~~~~~~~~~~~~
> edk2-89910a39dcfd/OvmfPkg/AcpiPlatformDxe/AcpiPlatform.c:164:3: note:
> Taking false branch
> #  if (QemuDetected ()) {
> #  ^
> edk2-89910a39dcfd/OvmfPkg/AcpiPlatformDxe/AcpiPlatform.c:174:3: note:
> Taking false branch
> #  if (EFI_ERROR (Status)) {
> #  ^
> edk2-89910a39dcfd/OvmfPkg/AcpiPlatformDxe/AcpiPlatform.c:180:10: note:
> Assuming 'Status' is equal to EFI_SUCCESS
> #  while (Status == EFI_SUCCESS) {
> #         ^~~~~~~~~~~~~~~~~~~~~
> edk2-89910a39dcfd/OvmfPkg/AcpiPlatformDxe/AcpiPlatform.c:180:3: note:
> Loop condition is true.  Entering loop body
> #  while (Status == EFI_SUCCESS) {
> #  ^
> edk2-89910a39dcfd/OvmfPkg/AcpiPlatformDxe/AcpiPlatform.c:182:14: note:
> Dereference of undefined pointer value
> #    Status = FwVol->ReadSection (
> #             ^~~~~~~~~~~~~~~~~~
> #  180|     while (Status == EFI_SUCCESS) {
> #  181|
> #  182|->     Status = FwVol->ReadSection (
> #  183|                         FwVol,
> #  184|                         (EFI_GUID*)PcdGetPtr (PcdAcpiTableStorageFile),

This is invalid because LocateFvInstanceWithTables() sets FwVol on
success.

Suppress the message by:
- assigning FwVol NULL first (this would replace the original report with
  "nullptr deref"),
- asserting that FwVol is no longer NULL, on success.

What's important here is that ASSERT() ends with ANALYZER_UNREACHABLE() on
failure.

Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Bugzilla: https://bugzilla.tianocore.org/show_bug.cgi?id=1710
Issue: scan-0991.txt
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---
 OvmfPkg/AcpiPlatformDxe/AcpiPlatform.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/OvmfPkg/AcpiPlatformDxe/AcpiPlatform.c b/OvmfPkg/AcpiPlatformDxe/AcpiPlatform.c
index f2c49953950b..2b529d58a15c 100644
--- a/OvmfPkg/AcpiPlatformDxe/AcpiPlatform.c
+++ b/OvmfPkg/AcpiPlatformDxe/AcpiPlatform.c
@@ -156,23 +156,30 @@ InstallOvmfFvTables (
   TableHandle  = 0;
 
   if (QemuDetected ()) {
     TableInstallFunction = QemuInstallAcpiTable;
   } else {
     TableInstallFunction = InstallAcpiTable;
   }
 
+  //
+  // set FwVol (and use an ASSERT() below) to suppress incorrect
+  // compiler/analyzer warnings
+  //
+  FwVol = NULL;
   //
   // Locate the firmware volume protocol
   //
   Status = LocateFvInstanceWithTables (&FwVol);
   if (EFI_ERROR (Status)) {
     return EFI_ABORTED;
   }
+  ASSERT (FwVol != NULL);
+
   //
   // Read tables from the storage file.
   //
   while (Status == EFI_SUCCESS) {
 
     Status = FwVol->ReadSection (
                       FwVol,
                       (EFI_GUID*)PcdGetPtr (PcdAcpiTableStorageFile),
-- 
2.19.1.3.g30247aa5d201



^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH 08/10] OvmfPkg: suppress "Value stored to ... is never read" analyzer warnings
  2019-04-12 23:31 [PATCH 00/10] patches for some warnings raised by "RH covscan" Laszlo Ersek
                   ` (6 preceding siblings ...)
  2019-04-12 23:31 ` [PATCH 07/10] OvmfPkg/AcpiPlatformDxe: suppress invalid "deref of undef pointer" warning Laszlo Ersek
@ 2019-04-12 23:31 ` Laszlo Ersek
  2019-04-14  8:03   ` [edk2-devel] " Jordan Justen
  2019-04-12 23:31 ` [PATCH 09/10] OvmfPkg/AcpiPlatformDxe: catch theoretical nullptr deref in Xen code Laszlo Ersek
                   ` (3 subsequent siblings)
  11 siblings, 1 reply; 52+ messages in thread
From: Laszlo Ersek @ 2019-04-12 23:31 UTC (permalink / raw)
  To: edk2-devel-groups-io
  Cc: Anthony Perard, Ard Biesheuvel, Jordan Justen, Julien Grall

RH covscan warns about assignments that it can determine are never
"consumed" later ("dead stores"). The idea behind the warning is
presumably that the programmer forgot to implement a dependent check
somewhere.

For each such warning that has been emitted for OvmfPkg,
the case is one of the following however:

- We assign a variable a value for (re-)initialization's sake, in
  preparation for further or future uses. This practice is safe (sometimes
  even recommended!), hence we should suppress these warnings.

- We capture a result or a computation in a variable, following a general
  programming pattern, but then decide to ignore the value in that
  particular case. This is again safe, and we should suppress these
  warnings too.

According to the Clang documentation at

  https://clang-analyzer.llvm.org/faq.html#dead_store

we should use

  (void)x;

See the logs below (produced originally for edk2-stable201903).

> Error: CLANG_WARNING:
> edk2-89910a39dcfd/OvmfPkg/AcpiPlatformDxe/Xen.c:156:3: warning: Value
> stored to 'NumberOfTableEntries' is never read
> #  NumberOfTableEntries = 0;
> #  ^                      ~
> edk2-89910a39dcfd/OvmfPkg/AcpiPlatformDxe/Xen.c:156:3: note: Value
> stored to 'NumberOfTableEntries' is never read
> #  NumberOfTableEntries = 0;
> #  ^                      ~
> #  154|     DsdtTable   = NULL;
> #  155|     TableHandle = 0;
> #  156|->   NumberOfTableEntries = 0;
> #  157|
> #  158|     //
>
> Error: CLANG_WARNING:
> edk2-89910a39dcfd/OvmfPkg/Library/PlatformBootManagerLib/QemuKernel.c:43:3:
> warning: Value stored to 'SetupSize' is never read
> #  SetupSize = 0;
> #  ^           ~
> edk2-89910a39dcfd/OvmfPkg/Library/PlatformBootManagerLib/QemuKernel.c:43:3:
> note: Value stored to 'SetupSize' is never read
> #  SetupSize = 0;
> #  ^           ~
> #   41|
> #   42|     SetupBuf = NULL;
> #   43|->   SetupSize = 0;
> #   44|     KernelBuf = NULL;
> #   45|     KernelInitialSize = 0;
>
> Error: CLANG_WARNING:
> edk2-89910a39dcfd/OvmfPkg/Library/SerializeVariablesLib/SerializeVariablesLib.c:609:9:
> warning: Value stored to 'VariableDataBufferSize' is never read
> #        VariableDataBufferSize = 0;
> #        ^                        ~
> edk2-89910a39dcfd/OvmfPkg/Library/SerializeVariablesLib/SerializeVariablesLib.c:609:9:
> note: Value stored to 'VariableDataBufferSize' is never read
> #        VariableDataBufferSize = 0;
> #        ^                        ~
> #  607|           FreePool (VariableData);
> #  608|           VariableData = NULL;
> #  609|->         VariableDataBufferSize = 0;
> #  610|         }
> #  611|         VariableData = AllocatePool (VariableDataSize);
>
> Error: CLANG_WARNING:
> edk2-89910a39dcfd/OvmfPkg/Library/VirtioLib/VirtioLib.c:125:3: warning:
> Value stored to 'RingPagesPtr' is never read
> #  RingPagesPtr += sizeof *Ring->Used.AvailEvent;
> #  ^               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> edk2-89910a39dcfd/OvmfPkg/Library/VirtioLib/VirtioLib.c:125:3: note:
> Value stored to 'RingPagesPtr' is never read
> #  RingPagesPtr += sizeof *Ring->Used.AvailEvent;
> #  ^               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> #  123|
> #  124|     Ring->Used.AvailEvent = (volatile VOID *) RingPagesPtr;
> #  125|->   RingPagesPtr += sizeof *Ring->Used.AvailEvent;
> #  126|
> #  127|     Ring->QueueSize = QueueSize;
>
> Error: CLANG_WARNING:
> edk2-89910a39dcfd/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c:1079:3:
> warning: Value stored to 'FwhInstance' is never read
> #  FwhInstance = (EFI_FW_VOL_INSTANCE *)
> #  ^             ~~~~~~~~~~~~~~~~~~~~~~~
> edk2-89910a39dcfd/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c:1079:3:
> note: Value stored to 'FwhInstance' is never read
> #  FwhInstance = (EFI_FW_VOL_INSTANCE *)
> #  ^             ~~~~~~~~~~~~~~~~~~~~~~~
> # 1077|     ASSERT_RETURN_ERROR (PcdStatus);
> # 1078|
> # 1079|->   FwhInstance = (EFI_FW_VOL_INSTANCE *)
> # 1080|       (
> # 1081|         (UINTN) ((UINT8 *) FwhInstance) + FwVolHeader->HeaderLength +
>
> Error: CLANG_WARNING:
> edk2-89910a39dcfd/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockServiceDxe.c:173:3:
> warning: Value stored to 'Status' is never read
> #  Status = gDS->RemoveMemorySpace (
> #  ^        ~~~~~~~~~~~~~~~~~~~~~~~~
> edk2-89910a39dcfd/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockServiceDxe.c:173:3:
> note: Value stored to 'Status' is never read
> #  Status = gDS->RemoveMemorySpace (
> #  ^        ~~~~~~~~~~~~~~~~~~~~~~~~
> #  171|     // Mark flash region as runtime memory
> #  172|     //
> #  173|->   Status = gDS->RemoveMemorySpace (
> #  174|                     BaseAddress,
> #  175|                     Length
>
> Error: CLANG_WARNING:
> edk2-89910a39dcfd/OvmfPkg/SataControllerDxe/SataController.c:231:3:
> warning: Value stored to 'DeviceUDmaMode' is never read
> #  DeviceUDmaMode = 0;
> #  ^                ~
> edk2-89910a39dcfd/OvmfPkg/SataControllerDxe/SataController.c:231:3:
> note: Value stored to 'DeviceUDmaMode' is never read
> #  DeviceUDmaMode = 0;
> #  ^                ~
> #  229|     UINT16    DeviceUDmaMode;
> #  230|
> #  231|->   DeviceUDmaMode = 0;
> #  232|
> #  233|     //
>
> Error: CLANG_WARNING:
> edk2-89910a39dcfd/OvmfPkg/VirtioGpuDxe/Gop.c:65:5: warning: Value stored
> to 'Status' is never read
> #    Status = VirtioGpuSetScanout (
> #    ^        ~~~~~~~~~~~~~~~~~~~~~
> edk2-89910a39dcfd/OvmfPkg/VirtioGpuDxe/Gop.c:65:5: note: Value stored to
> 'Status' is never read
> #    Status = VirtioGpuSetScanout (
> #    ^        ~~~~~~~~~~~~~~~~~~~~~
> #   63|       // by setting ResourceId=0 for it.
> #   64|       //
> #   65|->     Status = VirtioGpuSetScanout (
> #   66|                  VgpuGop->ParentBus, // VgpuDev
> #   67|                  0, 0, 0, 0,         // X, Y, Width, Height
>
> Error: CLANG_WARNING:
> edk2-89910a39dcfd/OvmfPkg/VirtioNetDxe/SnpReceive.c:165:3: warning:
> Value stored to 'RxPtr' is never read
> #  RxPtr += sizeof (UINT16);
> #  ^        ~~~~~~~~~~~~~~~
> edk2-89910a39dcfd/OvmfPkg/VirtioNetDxe/SnpReceive.c:165:3: note: Value
> stored to 'RxPtr' is never read
> #  RxPtr += sizeof (UINT16);
> #  ^        ~~~~~~~~~~~~~~~
> #  163|       *Protocol = (UINT16) ((RxPtr[0] << 8) | RxPtr[1]);
> #  164|     }
> #  165|->   RxPtr += sizeof (UINT16);
> #  166|
> #  167|     Status = EFI_SUCCESS;

Cc: Anthony Perard <anthony.perard@citrix.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Julien Grall <julien.grall@arm.com>
Bugzilla: https://bugzilla.tianocore.org/show_bug.cgi?id=1710
Issue: scan-0992.txt
Issue: scan-0996.txt
Issue: scan-0997.txt
Issue: scan-0998.txt
Issue: scan-1000.txt
Issue: scan-1001.txt
Issue: scan-1006.txt
Issue: scan-1011.txt
Issue: scan-1012.txt
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---
 OvmfPkg/AcpiPlatformDxe/Xen.c                                 | 5 +++++
 OvmfPkg/Library/PlatformBootManagerLib/QemuKernel.c           | 5 +++++
 OvmfPkg/Library/SerializeVariablesLib/SerializeVariablesLib.c | 4 ++++
 OvmfPkg/Library/VirtioLib/VirtioLib.c                         | 5 +++++
 OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c       | 5 +++++
 OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockServiceDxe.c    | 5 +++++
 OvmfPkg/SataControllerDxe/SataController.c                    | 5 +++++
 OvmfPkg/VirtioGpuDxe/Gop.c                                    | 6 ++++++
 OvmfPkg/VirtioNetDxe/SnpReceive.c                             | 5 +++++
 9 files changed, 45 insertions(+)

diff --git a/OvmfPkg/AcpiPlatformDxe/Xen.c b/OvmfPkg/AcpiPlatformDxe/Xen.c
index 357c60d23f4e..c8f275a8ee84 100644
--- a/OvmfPkg/AcpiPlatformDxe/Xen.c
+++ b/OvmfPkg/AcpiPlatformDxe/Xen.c
@@ -144,16 +144,21 @@ InstallXenTables (
   Fadt2Table  = NULL;
   Fadt1Table  = NULL;
   Facs2Table  = NULL;
   Facs1Table  = NULL;
   DsdtTable   = NULL;
   TableHandle = 0;
   NumberOfTableEntries = 0;
 
+  //
+  // Suppress "Value stored to ... is never read" analyzer warnings.
+  //
+  (VOID)NumberOfTableEntries;
+
   //
   // Try to find Xen ACPI tables
   //
   Status = GetXenAcpiRsdp (&XenAcpiRsdpStructurePtr);
   if (EFI_ERROR (Status)) {
     return Status;
   }
 
diff --git a/OvmfPkg/Library/PlatformBootManagerLib/QemuKernel.c b/OvmfPkg/Library/PlatformBootManagerLib/QemuKernel.c
index ddfef925edd3..fde8c40218a4 100644
--- a/OvmfPkg/Library/PlatformBootManagerLib/QemuKernel.c
+++ b/OvmfPkg/Library/PlatformBootManagerLib/QemuKernel.c
@@ -37,16 +37,21 @@ TryRunningQemuKernel (
   SetupSize = 0;
   KernelBuf = NULL;
   KernelInitialSize = 0;
   CommandLine = NULL;
   CommandLineSize = 0;
   InitrdData = NULL;
   InitrdSize = 0;
 
+  //
+  // Suppress "Value stored to ... is never read" analyzer warnings.
+  //
+  (VOID)SetupSize;
+
   if (!QemuFwCfgIsAvailable ()) {
     return EFI_NOT_FOUND;
   }
 
   QemuFwCfgSelectItem (QemuFwCfgItemKernelSize);
   KernelSize = (UINTN) QemuFwCfgRead64 ();
 
   QemuFwCfgSelectItem (QemuFwCfgItemKernelSetupSize);
diff --git a/OvmfPkg/Library/SerializeVariablesLib/SerializeVariablesLib.c b/OvmfPkg/Library/SerializeVariablesLib/SerializeVariablesLib.c
index a6cebcb54f6b..64fe9d9be543 100644
--- a/OvmfPkg/Library/SerializeVariablesLib/SerializeVariablesLib.c
+++ b/OvmfPkg/Library/SerializeVariablesLib/SerializeVariablesLib.c
@@ -596,16 +596,20 @@ SerializeVariablesIterateSystemVariables (
       //
       // The currently allocated VariableData buffer is too small,
       // so we allocate a larger buffer.
       //
       if (VariableDataBufferSize != 0) {
         FreePool (VariableData);
         VariableData = NULL;
         VariableDataBufferSize = 0;
+        //
+        // Suppress "Value stored to ... is never read" analyzer warnings.
+        //
+        (VOID)VariableDataBufferSize;
       }
       VariableData = AllocatePool (VariableDataSize);
       if (VariableData == NULL) {
         Status = EFI_OUT_OF_RESOURCES;
         break;
       }
       VariableDataBufferSize = VariableDataSize;
 
diff --git a/OvmfPkg/Library/VirtioLib/VirtioLib.c b/OvmfPkg/Library/VirtioLib/VirtioLib.c
index 555d2a5ce7c9..0e4b8b6b265e 100644
--- a/OvmfPkg/Library/VirtioLib/VirtioLib.c
+++ b/OvmfPkg/Library/VirtioLib/VirtioLib.c
@@ -113,16 +113,21 @@ VirtioRingInit (
   RingPagesPtr += sizeof *Ring->Used.Idx;
 
   Ring->Used.UsedElem = (volatile VOID *) RingPagesPtr;
   RingPagesPtr += sizeof *Ring->Used.UsedElem * QueueSize;
 
   Ring->Used.AvailEvent = (volatile VOID *) RingPagesPtr;
   RingPagesPtr += sizeof *Ring->Used.AvailEvent;
 
+  //
+  // Suppress "Value stored to ... is never read" analyzer warnings.
+  //
+  (VOID)RingPagesPtr;
+
   Ring->QueueSize = QueueSize;
   return EFI_SUCCESS;
 }
 
 
 /**
 
   Tear down the internal resources of a configured virtio ring.
diff --git a/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c b/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c
index edf438a422fa..ff6565865846 100644
--- a/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c
+++ b/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c
@@ -1071,16 +1071,21 @@ FvbInitialize (
   ASSERT_RETURN_ERROR (PcdStatus);
 
   FwhInstance = (EFI_FW_VOL_INSTANCE *)
     (
       (UINTN) ((UINT8 *) FwhInstance) + FwVolHeader->HeaderLength +
       (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))
     );
 
+  //
+  // Suppress "Value stored to ... is never read" analyzer warnings.
+  //
+  (VOID)FwhInstance;
+
   //
   // Module type specific hook.
   //
   InstallVirtualAddressChangeHandler ();
 
   PcdStatus = PcdSetBoolS (PcdOvmfFlashVariablesEnable, TRUE);
   ASSERT_RETURN_ERROR (PcdStatus);
   return EFI_SUCCESS;
diff --git a/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockServiceDxe.c b/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockServiceDxe.c
index 69b20916bc7c..979122f2e2fd 100644
--- a/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockServiceDxe.c
+++ b/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockServiceDxe.c
@@ -164,16 +164,21 @@ MarkIoMemoryRangeForRuntimeAccess (
   //
   // Mark flash region as runtime memory
   //
   Status = gDS->RemoveMemorySpace (
                   BaseAddress,
                   Length
                   );
 
+  //
+  // Suppress "Value stored to ... is never read" analyzer warnings.
+  //
+  (VOID)Status;
+
   Status = gDS->AddMemorySpace (
                   EfiGcdMemoryTypeMemoryMappedIo,
                   BaseAddress,
                   Length,
                   EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
                   );
   ASSERT_EFI_ERROR (Status);
 
diff --git a/OvmfPkg/SataControllerDxe/SataController.c b/OvmfPkg/SataControllerDxe/SataController.c
index 8d6a6bbb2286..0cf6b42c886a 100644
--- a/OvmfPkg/SataControllerDxe/SataController.c
+++ b/OvmfPkg/SataControllerDxe/SataController.c
@@ -219,16 +219,21 @@ CalculateBestUdmaMode (
   OUT UINT16            *SelectedMode
   )
 {
   UINT16    TempMode;
   UINT16    DeviceUDmaMode;
 
   DeviceUDmaMode = 0;
 
+  //
+  // Suppress "Value stored to ... is never read" analyzer warnings.
+  //
+  (VOID)DeviceUDmaMode;
+
   //
   // Check whether the WORD 88 (supported UltraDMA by drive) is valid
   //
   if ((IdentifyData->AtaData.field_validity & 0x04) == 0x00) {
     return EFI_UNSUPPORTED;
   }
 
   DeviceUDmaMode = IdentifyData->AtaData.ultra_dma_mode;
diff --git a/OvmfPkg/VirtioGpuDxe/Gop.c b/OvmfPkg/VirtioGpuDxe/Gop.c
index 0b2659d1d2b9..d0f81c349f73 100644
--- a/OvmfPkg/VirtioGpuDxe/Gop.c
+++ b/OvmfPkg/VirtioGpuDxe/Gop.c
@@ -57,16 +57,22 @@ ReleaseGopResources (
     // by setting ResourceId=0 for it.
     //
     Status = VirtioGpuSetScanout (
                VgpuGop->ParentBus, // VgpuDev
                0, 0, 0, 0,         // X, Y, Width, Height
                0,                  // ScanoutId
                0                   // ResourceId
                );
+
+    //
+    // Suppress "Value stored to ... is never read" analyzer warnings.
+    //
+    (VOID)Status;
+
     //
     // HACK BEGINS HERE
     //
     // According to the GPU Device section of the VirtIo specification, the
     // above operation is valid:
     //
     // "The driver can use resource_id = 0 to disable a scanout."
     //
diff --git a/OvmfPkg/VirtioNetDxe/SnpReceive.c b/OvmfPkg/VirtioNetDxe/SnpReceive.c
index cdee9a2aee47..51b2f8a4e370 100644
--- a/OvmfPkg/VirtioNetDxe/SnpReceive.c
+++ b/OvmfPkg/VirtioNetDxe/SnpReceive.c
@@ -153,16 +153,21 @@ VirtioNetReceive (
   }
   RxPtr += SIZE_OF_VNET (Mac);
 
   if (Protocol != NULL) {
     *Protocol = (UINT16) ((RxPtr[0] << 8) | RxPtr[1]);
   }
   RxPtr += sizeof (UINT16);
 
+  //
+  // Suppress "Value stored to ... is never read" analyzer warnings.
+  //
+  (VOID)RxPtr;
+
   Status = EFI_SUCCESS;
 
 RecycleDesc:
   ++Dev->RxLastUsed;
 
   //
   // virtio-0.9.5, 2.4.1 Supplying Buffers to The Device
   //
-- 
2.19.1.3.g30247aa5d201



^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH 09/10] OvmfPkg/AcpiPlatformDxe: catch theoretical nullptr deref in Xen code
  2019-04-12 23:31 [PATCH 00/10] patches for some warnings raised by "RH covscan" Laszlo Ersek
                   ` (7 preceding siblings ...)
  2019-04-12 23:31 ` [PATCH 08/10] OvmfPkg: suppress "Value stored to ... is never read" analyzer warnings Laszlo Ersek
@ 2019-04-12 23:31 ` Laszlo Ersek
  2019-04-15 17:28   ` [edk2-devel] " Philippe Mathieu-Daudé
  2019-04-12 23:31 ` [PATCH 10/10] OvmfPkg/BasePciCapLib: suppress invalid "nullptr deref" warning Laszlo Ersek
                   ` (2 subsequent siblings)
  11 siblings, 1 reply; 52+ messages in thread
From: Laszlo Ersek @ 2019-04-12 23:31 UTC (permalink / raw)
  To: edk2-devel-groups-io
  Cc: Anthony Perard, Ard Biesheuvel, Jordan Justen, Julien Grall

RH covscan justifiedly reports a path through InstallXenTables() where
DsdtTable can technically remain NULL.

If this occurs in practice, then the guest and the VMM are out of sync on
the interface contract. Catch the situation with a code snippet that halts
in RELEASE builds, and in DEBUG builds lets the platform DSC control the
assert disposition first (i.e. CPU exception, deadloop, or nothing).

> Error: CLANG_WARNING:
> edk2-89910a39dcfd/OvmfPkg/AcpiPlatformDxe/Xen.c:309:14: warning: Access
> to field 'Length' results in a dereference of a null pointer (loaded
> from variable 'DsdtTable')
> #             DsdtTable->Length,
> #             ^~~~~~~~~
> edk2-89910a39dcfd/OvmfPkg/AcpiPlatformDxe/Xen.c:154:3: note: Null
> pointer value stored to 'DsdtTable'
> #  DsdtTable   = NULL;
> #  ^~~~~~~~~~~~~~~~~~
> edk2-89910a39dcfd/OvmfPkg/AcpiPlatformDxe/Xen.c:162:3: note: Taking
> false branch
> #  if (EFI_ERROR (Status)) {
> #  ^
> edk2-89910a39dcfd/OvmfPkg/AcpiPlatformDxe/Xen.c:170:7: note: Assuming
> the condition is false
> #  if (XenAcpiRsdpStructurePtr->XsdtAddress) {
> #      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> edk2-89910a39dcfd/OvmfPkg/AcpiPlatformDxe/Xen.c:170:3: note: Taking
> false branch
> #  if (XenAcpiRsdpStructurePtr->XsdtAddress) {
> #  ^
> edk2-89910a39dcfd/OvmfPkg/AcpiPlatformDxe/Xen.c:220:12: note: Assuming
> the condition is false
> #  else if (XenAcpiRsdpStructurePtr->RsdtAddress) {
> #           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> edk2-89910a39dcfd/OvmfPkg/AcpiPlatformDxe/Xen.c:220:8: note: Taking
> false branch
> #  else if (XenAcpiRsdpStructurePtr->RsdtAddress) {
> #       ^
> edk2-89910a39dcfd/OvmfPkg/AcpiPlatformDxe/Xen.c:274:3: note: Taking
> false branch
> #  if (Fadt2Table) {
> #  ^
> edk2-89910a39dcfd/OvmfPkg/AcpiPlatformDxe/Xen.c:288:8: note: Taking
> false branch
> #  else if (Fadt1Table) {
> #       ^
> edk2-89910a39dcfd/OvmfPkg/AcpiPlatformDxe/Xen.c:309:14: note: Access to
> field 'Length' results in a dereference of a null pointer (loaded from
> variable 'DsdtTable')
> #             DsdtTable->Length,
> #             ^~~~~~~~~
> #  307|                AcpiProtocol,
> #  308|                DsdtTable,
> #  309|->              DsdtTable->Length,
> #  310|                &TableHandle
> #  311|                );

Cc: Anthony Perard <anthony.perard@citrix.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Julien Grall <julien.grall@arm.com>
Bugzilla: https://bugzilla.tianocore.org/show_bug.cgi?id=1710
Issue: scan-0993.txt
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---
 OvmfPkg/AcpiPlatformDxe/Xen.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/OvmfPkg/AcpiPlatformDxe/Xen.c b/OvmfPkg/AcpiPlatformDxe/Xen.c
index c8f275a8ee84..b21d3db74dc8 100644
--- a/OvmfPkg/AcpiPlatformDxe/Xen.c
+++ b/OvmfPkg/AcpiPlatformDxe/Xen.c
@@ -295,18 +295,25 @@ InstallXenTables (
                &TableHandle
                );
     if (EFI_ERROR (Status)) {
       return Status;
     }
   }
 
   //
-  // Install DSDT table.
+  // Install DSDT table. If we reached this point without finding the DSDT,
+  // then we're out of sync with the hypervisor, and cannot continue.
   //
+  if (DsdtTable == NULL) {
+    DEBUG ((DEBUG_ERROR, "%a: no DSDT found\n", __FUNCTION__));
+    ASSERT (FALSE);
+    CpuDeadLoop ();
+  }
+
   Status = InstallAcpiTable (
              AcpiProtocol,
              DsdtTable,
              DsdtTable->Length,
              &TableHandle
              );
   if (EFI_ERROR (Status)) {
     return Status;
-- 
2.19.1.3.g30247aa5d201



^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH 10/10] OvmfPkg/BasePciCapLib: suppress invalid "nullptr deref" warning
  2019-04-12 23:31 [PATCH 00/10] patches for some warnings raised by "RH covscan" Laszlo Ersek
                   ` (8 preceding siblings ...)
  2019-04-12 23:31 ` [PATCH 09/10] OvmfPkg/AcpiPlatformDxe: catch theoretical nullptr deref in Xen code Laszlo Ersek
@ 2019-04-12 23:31 ` Laszlo Ersek
  2019-04-15 17:31   ` [edk2-devel] " Philippe Mathieu-Daudé
  2019-04-12 23:36 ` [PATCH 00/10] patches for some warnings raised by "RH covscan" Ard Biesheuvel
  2019-04-18 14:20 ` [edk2-devel] " Laszlo Ersek
  11 siblings, 1 reply; 52+ messages in thread
From: Laszlo Ersek @ 2019-04-12 23:31 UTC (permalink / raw)
  To: edk2-devel-groups-io; +Cc: Ard Biesheuvel, Jordan Justen

RH covscan reports the following "nullptr deref" warning:

> Error: CLANG_WARNING:
> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:312:5:
> warning: Dereference of null pointer
> #    InstanceZero->NumInstancesUnion.NumInstances++;
> #    ^
> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:509:7:
> note: Assuming 'OutCapList' is not equal to NULL
> #  if (OutCapList == NULL) {
> #      ^~~~~~~~~~~~~~~~~~
> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:509:3:
> note: Taking false branch
> #  if (OutCapList == NULL) {
> #  ^
> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:518:7:
> note: Assuming the condition is false
> #  if (OutCapList->Capabilities == NULL) {
> #      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:518:3:
> note: Taking false branch
> #  if (OutCapList->Capabilities == NULL) {
> #  ^
> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:529:7:
> note: Assuming 'CapHdrOffsets' is not equal to NULL
> #  if (CapHdrOffsets == NULL) {
> #      ^~~~~~~~~~~~~~~~~~~~~
> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:529:3:
> note: Taking false branch
> #  if (CapHdrOffsets == NULL) {
> #  ^
> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:546:3:
> note: Taking false branch
> #  if (RETURN_ERROR (Status)) {
> #  ^
> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:549:7:
> note: Assuming the condition is true
> #  if ((PciStatusReg & EFI_PCI_STATUS_CAPABILITY) != 0) {
> #      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:549:3:
> note: Taking true branch
> #  if ((PciStatusReg & EFI_PCI_STATUS_CAPABILITY) != 0) {
> #  ^
> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:557:5:
> note: Taking false branch
> #    if (RETURN_ERROR (Status)) {
> #    ^
> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:565:12:
> note: Assuming 'NormalCapHdrOffset' is > 0
> #    while (NormalCapHdrOffset > 0) {
> #           ^~~~~~~~~~~~~~~~~~~~~~
> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:565:5:
> note: Loop condition is true.  Entering loop body
> #    while (NormalCapHdrOffset > 0) {
> #    ^
> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:570:7:
> note: Taking false branch
> #      if (RETURN_ERROR (Status)) {
> #      ^
> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:574:16:
> note: Calling 'InsertPciCap'
> #      Status = InsertPciCap (OutCapList, CapHdrOffsets, PciCapNormal,
> #               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:235:3:
> note: Null pointer value stored to 'InstanceZero'
> #  InstanceZero = NULL;
> #  ^~~~~~~~~~~~~~~~~~~
> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:243:7:
> note: Assuming 'PciCap' is not equal to NULL
> #  if (PciCap == NULL) {
> #      ^~~~~~~~~~~~~~
> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:243:3:
> note: Taking false branch
> #  if (PciCap == NULL) {
> #  ^
> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:259:3:
> note: Taking false branch
> #  if (RETURN_ERROR (Status)) {
> #  ^
> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:297:3:
> note: Taking false branch
> #  if (RETURN_ERROR (Status)) {
> #  ^
> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:311:7:
> note: Assuming the condition is true
> #  if (PciCap->Key.Instance > 0) {
> #      ^~~~~~~~~~~~~~~~~~~~~~~~
> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:311:3:
> note: Taking true branch
> #  if (PciCap->Key.Instance > 0) {
> #  ^
> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:312:5:
> note: Dereference of null pointer
> #    InstanceZero->NumInstancesUnion.NumInstances++;
> #    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> #  310|     //
> #  311|     if (PciCap->Key.Instance > 0) {
> #  312|->     InstanceZero->NumInstancesUnion.NumInstances++;
> #  313|     }
> #  314|     return RETURN_SUCCESS;

The warning is invalid: the flagged dereferencing of "InstanceZero" is
gated by a condition that is only satisfied if we dereference
"InstanceZero" *first*.

(Perhaps the analyzer assumes that the OrderedCollectionInsert() call,
just before line 259, can change the value of "PciCap->Key.Instance" via
the last argument:

   254    //
   255    // Add PciCap to CapList.
   256    //
   257    Status = OrderedCollectionInsert (CapList->Capabilities, &PciCapEntry,
   258               PciCap);
   259    if (RETURN_ERROR (Status)) {

That assumption is incorrect.)

Add a comment and an ASSERT().

Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Bugzilla: https://bugzilla.tianocore.org/show_bug.cgi?id=1710
Issue: scan-0994.txt
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---
 OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c b/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c
index 4968d2b478db..c6f2c726509f 100644
--- a/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c
+++ b/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c
@@ -298,16 +298,23 @@ InsertPciCap (
     goto DeletePciCapFromCapList;
   }
 
   //
   // Now we can bump the instance count maintained in Instance#0, if PciCap is
   // not the first instance of (Domain, CapId).
   //
   if (PciCap->Key.Instance > 0) {
+    //
+    // Suppress invalid "nullptr dereference" compiler/analyzer warnings: the
+    // only way for "PciCap->Key.Instance" to be positive here is for it to
+    // have been assigned *from* dereferencing "InstanceZero" above.
+    //
+    ASSERT (InstanceZero != NULL);
+
     InstanceZero->NumInstancesUnion.NumInstances++;
   }
   return RETURN_SUCCESS;
 
 DeletePciCapFromCapList:
   OrderedCollectionDelete (CapList->Capabilities, PciCapEntry, NULL);
 
 FreePciCap:
-- 
2.19.1.3.g30247aa5d201


^ permalink raw reply related	[flat|nested] 52+ messages in thread

* Re: [PATCH 00/10] patches for some warnings raised by "RH covscan"
  2019-04-12 23:31 [PATCH 00/10] patches for some warnings raised by "RH covscan" Laszlo Ersek
                   ` (9 preceding siblings ...)
  2019-04-12 23:31 ` [PATCH 10/10] OvmfPkg/BasePciCapLib: suppress invalid "nullptr deref" warning Laszlo Ersek
@ 2019-04-12 23:36 ` Ard Biesheuvel
  2019-04-15 16:16   ` Laszlo Ersek
  2019-04-18 14:20 ` [edk2-devel] " Laszlo Ersek
  11 siblings, 1 reply; 52+ messages in thread
From: Ard Biesheuvel @ 2019-04-12 23:36 UTC (permalink / raw)
  To: Laszlo Ersek
  Cc: edk2-devel-groups-io, Anthony Perard, Ard Biesheuvel, Bob Feng,
	Jordan Justen, Julien Grall, Liming Gao, Michael D Kinney,
	Yonghong Zhu

On Fri, 12 Apr 2019 at 16:31, Laszlo Ersek <lersek@redhat.com> wrote:
>
> Bugzilla: https://bugzilla.tianocore.org/show_bug.cgi?id=1710
> Repo:     https://github.com/lersek/edk2.git
> Branch:   covscan_bz_1710
>
> "covscan" is an internal service at Red Hat that lets associates run
> static analysis tools on Fedora/RHEL packages. It drives a number of
> static analyzers.
>
> While covscan's existence is not "secret" (if you google it, you get a
> bunch of hits in the Red Hat Bugzilla), I can *not* use or offer covscan
> as a general upstream tool; for that the TianoCore community will have
> to build its own service / environment.
>
> Anyway, "covscan" happened to drop a bunch of reports on me for...
> "reasons", and so I turned a short 10 hour workday into yet anoher
> normal 15 hour workday (stealing some free time whence there was none)
> in order to do something, up-stream, about the warnings that affected
> OvmfPkg. No claim is made about the completeness of the scan's coverage.
>
> Some of the patches seek to suppress warnings, some strive to remedy
> valid-looking issues. We should not spend much time on this series.
>
> Cc: Anthony Perard <anthony.perard@citrix.com>
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Cc: Bob Feng <bob.c.feng@intel.com>
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Julien Grall <julien.grall@arm.com>
> Cc: Liming Gao <liming.gao@intel.com>
> Cc: Michael D Kinney <michael.d.kinney@intel.com>
> Cc: Yonghong Zhu <yonghong.zhu@intel.com>
>
> Thanks
> Laszlo
>
> Laszlo Ersek (10):
>   MdePkg/PiFirmwareFile: express IS_SECTION2 in terms of SECTION_SIZE
>   MdePkg/PiFirmwareFile: fix undefined behavior in SECTION_SIZE
>   BaseTools/PiFirmwareFile: fix undefined behavior in SECTION_SIZE
>   MdePkg/PiFirmwareFile: fix undefined behavior in FFS_FILE_SIZE
>   OvmfPkg/Sec: fix out-of-bounds reads
>   OvmfPkg/QemuVideoDxe: avoid arithmetic on null pointer
>   OvmfPkg/AcpiPlatformDxe: suppress invalid "deref of undef pointer"
>     warning
>   OvmfPkg: suppress "Value stored to ... is never read" analyzer
>     warnings
>   OvmfPkg/AcpiPlatformDxe: catch theoretical nullptr deref in Xen code
>   OvmfPkg/BasePciCapLib: suppress invalid "nullptr deref" warning
>

Thanks for the cleanup. I wasn't cc'ed on all patches, but this looks
good afaict.

Where needed,

Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>


>  BaseTools/Source/C/Include/Common/PiFirmwareFile.h            |  7 +++++-
>  MdePkg/Include/Pi/PiFirmwareFile.h                            | 26 ++++++++++++++++----
>  OvmfPkg/AcpiPlatformDxe/AcpiPlatform.c                        |  7 ++++++
>  OvmfPkg/AcpiPlatformDxe/Xen.c                                 | 14 ++++++++++-
>  OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c                 |  7 ++++++
>  OvmfPkg/Library/PlatformBootManagerLib/QemuKernel.c           |  5 ++++
>  OvmfPkg/Library/SerializeVariablesLib/SerializeVariablesLib.c |  4 +++
>  OvmfPkg/Library/VirtioLib/VirtioLib.c                         |  5 ++++
>  OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c       |  5 ++++
>  OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockServiceDxe.c    |  5 ++++
>  OvmfPkg/QemuVideoDxe/VbeShim.c                                |  2 +-
>  OvmfPkg/SataControllerDxe/SataController.c                    |  5 ++++
>  OvmfPkg/Sec/SecMain.c                                         |  6 ++---
>  OvmfPkg/VirtioGpuDxe/Gop.c                                    |  6 +++++
>  OvmfPkg/VirtioNetDxe/SnpReceive.c                             |  5 ++++
>  15 files changed, 98 insertions(+), 11 deletions(-)
>
> --
> 2.19.1.3.g30247aa5d201
>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [edk2-devel] [PATCH 02/10] MdePkg/PiFirmwareFile: fix undefined behavior in SECTION_SIZE
  2019-04-12 23:31 ` [PATCH 02/10] MdePkg/PiFirmwareFile: fix undefined behavior in SECTION_SIZE Laszlo Ersek
@ 2019-04-14  7:19   ` Jordan Justen
  2019-04-15 16:15     ` Laszlo Ersek
  0 siblings, 1 reply; 52+ messages in thread
From: Jordan Justen @ 2019-04-14  7:19 UTC (permalink / raw)
  To: Laszlo Ersek, edk2-devel-groups-io, Michael D Kinney; +Cc: Liming Gao

On 2019-04-12 16:31:20, Laszlo Ersek wrote:
> RH covscan justifiedly reports that accessing
> "EFI_COMMON_SECTION_HEADER.Size", which is of type UINT8[3], through a
> (UINT32*), is undefined behavior:
> 
> > Error: OVERRUN (CWE-119):
> > edk2-89910a39dcfd/OvmfPkg/Sec/SecMain.c:178: overrun-local: Overrunning
> > array of 3 bytes at byte offset 3 by dereferencing pointer
> > "(UINT32 *)((EFI_COMMON_SECTION_HEADER *)(UINTN)Section)->Size".
> > #  176|       Section = (EFI_COMMON_SECTION_HEADER*)(UINTN) CurrentAddress;
> > #  177|
> > #  178|->     Size = SECTION_SIZE (Section);
> > #  179|       if (Size < sizeof (*Section)) {
> > #  180|         return EFI_VOLUME_CORRUPTED;
> 
> Fix this by introducing EFI_COMMON_SECTION_HEADER_UNION, and expressing
> SECTION_SIZE() in terms of "EFI_COMMON_SECTION_HEADER_UNION.Uint32".
> 
> Cc: Liming Gao <liming.gao@intel.com>
> Cc: Michael D Kinney <michael.d.kinney@intel.com>
> Bugzilla: https://bugzilla.tianocore.org/show_bug.cgi?id=1710
> Issue: scan-1007.txt
> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> ---
>  MdePkg/Include/Pi/PiFirmwareFile.h | 10 +++++++++-
>  1 file changed, 9 insertions(+), 1 deletion(-)
> 
> diff --git a/MdePkg/Include/Pi/PiFirmwareFile.h b/MdePkg/Include/Pi/PiFirmwareFile.h
> index a9f3bcc4eb8e..4fce8298d1c0 100644
> --- a/MdePkg/Include/Pi/PiFirmwareFile.h
> +++ b/MdePkg/Include/Pi/PiFirmwareFile.h
> @@ -229,16 +229,24 @@ typedef struct {
>    ///
>    UINT8             Size[3];
>    EFI_SECTION_TYPE  Type;
>    ///
>    /// Declares the section type.
>    ///
>  } EFI_COMMON_SECTION_HEADER;
>  
> +///
> +/// Union that permits accessing EFI_COMMON_SECTION_HEADER as a UINT32 object.
> +///
> +typedef union {
> +  EFI_COMMON_SECTION_HEADER Hdr;
> +  UINT32                    Uint32;
> +} EFI_COMMON_SECTION_HEADER_UNION;
> +
>  typedef struct {
>    ///
>    /// A 24-bit unsigned integer that contains the total size of the section in bytes,
>    /// including the EFI_COMMON_SECTION_HEADER.
>    ///
>    UINT8             Size[3];
>  
>    EFI_SECTION_TYPE  Type;
> @@ -476,17 +484,17 @@ typedef struct {
>    /// A UINT16 that represents a particular build. Subsequent builds have monotonically
>    /// increasing build numbers relative to earlier builds.
>    ///
>    UINT16                        BuildNumber;
>    CHAR16                        VersionString[1];
>  } EFI_VERSION_SECTION2;
>  
>  #define SECTION_SIZE(SectionHeaderPtr) \
> -    ((UINT32) (*((UINT32 *) ((EFI_COMMON_SECTION_HEADER *) (UINTN) SectionHeaderPtr)->Size) & 0x00ffffff))
> +    (((EFI_COMMON_SECTION_HEADER_UNION *) (UINTN) (SectionHeaderPtr))->Uint32 & 0x00ffffff)

Mike, all,

Can we add a typedef for EFI_COMMON_SECTION_HEADER_UNION if it's not
in the PI spec?

If it's not allowed, I think something like this might work too:

#define SECTION_SIZE(SectionHeaderPtr) \
    (*((UINT32*)(UINTN)(SectionHeaderPtr)) & 0x00ffffff)

Then again, I see SECTION_SIZE is not in the spec, so maybe it's ok to
add the typedef.

-Jordan

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [edk2-devel] [PATCH 08/10] OvmfPkg: suppress "Value stored to ... is never read" analyzer warnings
  2019-04-12 23:31 ` [PATCH 08/10] OvmfPkg: suppress "Value stored to ... is never read" analyzer warnings Laszlo Ersek
@ 2019-04-14  8:03   ` Jordan Justen
  2019-04-15 16:25     ` Laszlo Ersek
  0 siblings, 1 reply; 52+ messages in thread
From: Jordan Justen @ 2019-04-14  8:03 UTC (permalink / raw)
  To: Laszlo Ersek, edk2-devel-groups-io
  Cc: Anthony Perard, Ard Biesheuvel, Julien Grall

On 2019-04-12 16:31:26, Laszlo Ersek wrote:
> RH covscan warns about assignments that it can determine are never
> "consumed" later ("dead stores"). The idea behind the warning is
> presumably that the programmer forgot to implement a dependent check
> somewhere.
> 
> For each such warning that has been emitted for OvmfPkg,
> the case is one of the following however:
> 
> - We assign a variable a value for (re-)initialization's sake, in
>   preparation for further or future uses. This practice is safe (sometimes
>   even recommended!), hence we should suppress these warnings.
> 
> - We capture a result or a computation in a variable, following a general
>   programming pattern, but then decide to ignore the value in that
>   particular case. This is again safe, and we should suppress these
>   warnings too.
> 
> According to the Clang documentation at
> 
>   https://clang-analyzer.llvm.org/faq.html#dead_store
> 
> we should use
> 
>   (void)x;
> 
> See the logs below (produced originally for edk2-stable201903).
> 
> > Error: CLANG_WARNING:
> > edk2-89910a39dcfd/OvmfPkg/AcpiPlatformDxe/Xen.c:156:3: warning: Value
> > stored to 'NumberOfTableEntries' is never read
> > #  NumberOfTableEntries = 0;
> > #  ^                      ~
> > edk2-89910a39dcfd/OvmfPkg/AcpiPlatformDxe/Xen.c:156:3: note: Value
> > stored to 'NumberOfTableEntries' is never read
> > #  NumberOfTableEntries = 0;
> > #  ^                      ~
> > #  154|     DsdtTable   = NULL;
> > #  155|     TableHandle = 0;
> > #  156|->   NumberOfTableEntries = 0;
> > #  157|
> > #  158|     //
> >
> > Error: CLANG_WARNING:
> > edk2-89910a39dcfd/OvmfPkg/Library/PlatformBootManagerLib/QemuKernel.c:43:3:
> > warning: Value stored to 'SetupSize' is never read
> > #  SetupSize = 0;
> > #  ^           ~
> > edk2-89910a39dcfd/OvmfPkg/Library/PlatformBootManagerLib/QemuKernel.c:43:3:
> > note: Value stored to 'SetupSize' is never read
> > #  SetupSize = 0;
> > #  ^           ~
> > #   41|
> > #   42|     SetupBuf = NULL;
> > #   43|->   SetupSize = 0;
> > #   44|     KernelBuf = NULL;
> > #   45|     KernelInitialSize = 0;
> >
> > Error: CLANG_WARNING:
> > edk2-89910a39dcfd/OvmfPkg/Library/SerializeVariablesLib/SerializeVariablesLib.c:609:9:
> > warning: Value stored to 'VariableDataBufferSize' is never read
> > #        VariableDataBufferSize = 0;
> > #        ^                        ~
> > edk2-89910a39dcfd/OvmfPkg/Library/SerializeVariablesLib/SerializeVariablesLib.c:609:9:
> > note: Value stored to 'VariableDataBufferSize' is never read
> > #        VariableDataBufferSize = 0;
> > #        ^                        ~
> > #  607|           FreePool (VariableData);
> > #  608|           VariableData = NULL;
> > #  609|->         VariableDataBufferSize = 0;
> > #  610|         }
> > #  611|         VariableData = AllocatePool (VariableDataSize);
> >
> > Error: CLANG_WARNING:
> > edk2-89910a39dcfd/OvmfPkg/Library/VirtioLib/VirtioLib.c:125:3: warning:
> > Value stored to 'RingPagesPtr' is never read
> > #  RingPagesPtr += sizeof *Ring->Used.AvailEvent;
> > #  ^               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> > edk2-89910a39dcfd/OvmfPkg/Library/VirtioLib/VirtioLib.c:125:3: note:
> > Value stored to 'RingPagesPtr' is never read
> > #  RingPagesPtr += sizeof *Ring->Used.AvailEvent;
> > #  ^               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> > #  123|
> > #  124|     Ring->Used.AvailEvent = (volatile VOID *) RingPagesPtr;
> > #  125|->   RingPagesPtr += sizeof *Ring->Used.AvailEvent;
> > #  126|
> > #  127|     Ring->QueueSize = QueueSize;
> >
> > Error: CLANG_WARNING:
> > edk2-89910a39dcfd/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c:1079:3:
> > warning: Value stored to 'FwhInstance' is never read
> > #  FwhInstance = (EFI_FW_VOL_INSTANCE *)
> > #  ^             ~~~~~~~~~~~~~~~~~~~~~~~
> > edk2-89910a39dcfd/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c:1079:3:
> > note: Value stored to 'FwhInstance' is never read
> > #  FwhInstance = (EFI_FW_VOL_INSTANCE *)
> > #  ^             ~~~~~~~~~~~~~~~~~~~~~~~
> > # 1077|     ASSERT_RETURN_ERROR (PcdStatus);
> > # 1078|
> > # 1079|->   FwhInstance = (EFI_FW_VOL_INSTANCE *)
> > # 1080|       (
> > # 1081|         (UINTN) ((UINT8 *) FwhInstance) + FwVolHeader->HeaderLength +
> >
> > Error: CLANG_WARNING:
> > edk2-89910a39dcfd/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockServiceDxe.c:173:3:
> > warning: Value stored to 'Status' is never read
> > #  Status = gDS->RemoveMemorySpace (
> > #  ^        ~~~~~~~~~~~~~~~~~~~~~~~~
> > edk2-89910a39dcfd/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockServiceDxe.c:173:3:
> > note: Value stored to 'Status' is never read
> > #  Status = gDS->RemoveMemorySpace (
> > #  ^        ~~~~~~~~~~~~~~~~~~~~~~~~
> > #  171|     // Mark flash region as runtime memory
> > #  172|     //
> > #  173|->   Status = gDS->RemoveMemorySpace (
> > #  174|                     BaseAddress,
> > #  175|                     Length
> >
> > Error: CLANG_WARNING:
> > edk2-89910a39dcfd/OvmfPkg/SataControllerDxe/SataController.c:231:3:
> > warning: Value stored to 'DeviceUDmaMode' is never read
> > #  DeviceUDmaMode = 0;
> > #  ^                ~
> > edk2-89910a39dcfd/OvmfPkg/SataControllerDxe/SataController.c:231:3:
> > note: Value stored to 'DeviceUDmaMode' is never read
> > #  DeviceUDmaMode = 0;
> > #  ^                ~
> > #  229|     UINT16    DeviceUDmaMode;
> > #  230|
> > #  231|->   DeviceUDmaMode = 0;
> > #  232|
> > #  233|     //
> >
> > Error: CLANG_WARNING:
> > edk2-89910a39dcfd/OvmfPkg/VirtioGpuDxe/Gop.c:65:5: warning: Value stored
> > to 'Status' is never read
> > #    Status = VirtioGpuSetScanout (
> > #    ^        ~~~~~~~~~~~~~~~~~~~~~
> > edk2-89910a39dcfd/OvmfPkg/VirtioGpuDxe/Gop.c:65:5: note: Value stored to
> > 'Status' is never read
> > #    Status = VirtioGpuSetScanout (
> > #    ^        ~~~~~~~~~~~~~~~~~~~~~
> > #   63|       // by setting ResourceId=0 for it.
> > #   64|       //
> > #   65|->     Status = VirtioGpuSetScanout (
> > #   66|                  VgpuGop->ParentBus, // VgpuDev
> > #   67|                  0, 0, 0, 0,         // X, Y, Width, Height
> >
> > Error: CLANG_WARNING:
> > edk2-89910a39dcfd/OvmfPkg/VirtioNetDxe/SnpReceive.c:165:3: warning:
> > Value stored to 'RxPtr' is never read
> > #  RxPtr += sizeof (UINT16);
> > #  ^        ~~~~~~~~~~~~~~~
> > edk2-89910a39dcfd/OvmfPkg/VirtioNetDxe/SnpReceive.c:165:3: note: Value
> > stored to 'RxPtr' is never read
> > #  RxPtr += sizeof (UINT16);
> > #  ^        ~~~~~~~~~~~~~~~
> > #  163|       *Protocol = (UINT16) ((RxPtr[0] << 8) | RxPtr[1]);
> > #  164|     }
> > #  165|->   RxPtr += sizeof (UINT16);
> > #  166|
> > #  167|     Status = EFI_SUCCESS;
> 
> Cc: Anthony Perard <anthony.perard@citrix.com>
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Julien Grall <julien.grall@arm.com>
> Bugzilla: https://bugzilla.tianocore.org/show_bug.cgi?id=1710
> Issue: scan-0992.txt
> Issue: scan-0996.txt
> Issue: scan-0997.txt
> Issue: scan-0998.txt
> Issue: scan-1000.txt
> Issue: scan-1001.txt
> Issue: scan-1006.txt
> Issue: scan-1011.txt
> Issue: scan-1012.txt
> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> ---
>  OvmfPkg/AcpiPlatformDxe/Xen.c                                 | 5 +++++
>  OvmfPkg/Library/PlatformBootManagerLib/QemuKernel.c           | 5 +++++
>  OvmfPkg/Library/SerializeVariablesLib/SerializeVariablesLib.c | 4 ++++
>  OvmfPkg/Library/VirtioLib/VirtioLib.c                         | 5 +++++
>  OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c       | 5 +++++
>  OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockServiceDxe.c    | 5 +++++
>  OvmfPkg/SataControllerDxe/SataController.c                    | 5 +++++
>  OvmfPkg/VirtioGpuDxe/Gop.c                                    | 6 ++++++
>  OvmfPkg/VirtioNetDxe/SnpReceive.c                             | 5 +++++
>  9 files changed, 45 insertions(+)
> 
> diff --git a/OvmfPkg/AcpiPlatformDxe/Xen.c b/OvmfPkg/AcpiPlatformDxe/Xen.c
> index 357c60d23f4e..c8f275a8ee84 100644
> --- a/OvmfPkg/AcpiPlatformDxe/Xen.c
> +++ b/OvmfPkg/AcpiPlatformDxe/Xen.c
> @@ -144,16 +144,21 @@ InstallXenTables (
>    Fadt2Table  = NULL;
>    Fadt1Table  = NULL;
>    Facs2Table  = NULL;
>    Facs1Table  = NULL;
>    DsdtTable   = NULL;
>    TableHandle = 0;
>    NumberOfTableEntries = 0;
>
> +  //
> +  // Suppress "Value stored to ... is never read" analyzer warnings.
> +  //
> +  (VOID)NumberOfTableEntries;
> +

I've seen this solution to shut up the compiler for similar reasons,
and it kind of bugs me.

It looks like both paths of the if & else initialize
NumberOfTableEntries, so maybe we can just drop setting it to 0?

I looked at FwhInstance too, and it doesn't look like it is used after
being set. So, maybe that should just be dropped?

I guess both of your bullet points give arguments allowing the unused
set.

Rather than adding "Suppress..." comments everywhere, maybe a global
macro could be defined for similar uses in EDK II?

//
// Suppress "Value stored to ... is never read" analyzer warnings.
//
#define IGNORE_UNUSED_ASSIGNMENT(var) ((VOID)var)

Then again, I guess we decided to suppress this in EDK II compiler
warnings with -Wno-unused-but-set-variable.

So, can you adjust the RH covscan tool settings to similarly ignore
these warnings?

-Jordan

>    //
>    // Try to find Xen ACPI tables
>    //
>    Status = GetXenAcpiRsdp (&XenAcpiRsdpStructurePtr);
>    if (EFI_ERROR (Status)) {
>      return Status;
>    }
>
> diff --git a/OvmfPkg/Library/PlatformBootManagerLib/QemuKernel.c b/OvmfPkg/Library/PlatformBootManagerLib/QemuKernel.c
> index ddfef925edd3..fde8c40218a4 100644
> --- a/OvmfPkg/Library/PlatformBootManagerLib/QemuKernel.c
> +++ b/OvmfPkg/Library/PlatformBootManagerLib/QemuKernel.c
> @@ -37,16 +37,21 @@ TryRunningQemuKernel (
>    SetupSize = 0;
>    KernelBuf = NULL;
>    KernelInitialSize = 0;
>    CommandLine = NULL;
>    CommandLineSize = 0;
>    InitrdData = NULL;
>    InitrdSize = 0;
>
> +  //
> +  // Suppress "Value stored to ... is never read" analyzer warnings.
> +  //
> +  (VOID)SetupSize;
> +
>    if (!QemuFwCfgIsAvailable ()) {
>      return EFI_NOT_FOUND;
>    }
>
>    QemuFwCfgSelectItem (QemuFwCfgItemKernelSize);
>    KernelSize = (UINTN) QemuFwCfgRead64 ();
>
>    QemuFwCfgSelectItem (QemuFwCfgItemKernelSetupSize);
> diff --git a/OvmfPkg/Library/SerializeVariablesLib/SerializeVariablesLib.c b/OvmfPkg/Library/SerializeVariablesLib/SerializeVariablesLib.c
> index a6cebcb54f6b..64fe9d9be543 100644
> --- a/OvmfPkg/Library/SerializeVariablesLib/SerializeVariablesLib.c
> +++ b/OvmfPkg/Library/SerializeVariablesLib/SerializeVariablesLib.c
> @@ -596,16 +596,20 @@ SerializeVariablesIterateSystemVariables (
>        //
>        // The currently allocated VariableData buffer is too small,
>        // so we allocate a larger buffer.
>        //
>        if (VariableDataBufferSize != 0) {
>          FreePool (VariableData);
>          VariableData = NULL;
>          VariableDataBufferSize = 0;
> +        //
> +        // Suppress "Value stored to ... is never read" analyzer warnings.
> +        //
> +        (VOID)VariableDataBufferSize;
>        }
>        VariableData = AllocatePool (VariableDataSize);
>        if (VariableData == NULL) {
>          Status = EFI_OUT_OF_RESOURCES;
>          break;
>        }
>        VariableDataBufferSize = VariableDataSize;
>
> diff --git a/OvmfPkg/Library/VirtioLib/VirtioLib.c b/OvmfPkg/Library/VirtioLib/VirtioLib.c
> index 555d2a5ce7c9..0e4b8b6b265e 100644
> --- a/OvmfPkg/Library/VirtioLib/VirtioLib.c
> +++ b/OvmfPkg/Library/VirtioLib/VirtioLib.c
> @@ -113,16 +113,21 @@ VirtioRingInit (
>    RingPagesPtr += sizeof *Ring->Used.Idx;
>
>    Ring->Used.UsedElem = (volatile VOID *) RingPagesPtr;
>    RingPagesPtr += sizeof *Ring->Used.UsedElem * QueueSize;
>
>    Ring->Used.AvailEvent = (volatile VOID *) RingPagesPtr;
>    RingPagesPtr += sizeof *Ring->Used.AvailEvent;
>
> +  //
> +  // Suppress "Value stored to ... is never read" analyzer warnings.
> +  //
> +  (VOID)RingPagesPtr;
> +
>    Ring->QueueSize = QueueSize;
>    return EFI_SUCCESS;
>  }
>
>
>  /**
>
>    Tear down the internal resources of a configured virtio ring.
> diff --git a/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c b/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c
> index edf438a422fa..ff6565865846 100644
> --- a/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c
> +++ b/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c
> @@ -1071,16 +1071,21 @@ FvbInitialize (
>    ASSERT_RETURN_ERROR (PcdStatus);
>
>    FwhInstance = (EFI_FW_VOL_INSTANCE *)
>      (
>        (UINTN) ((UINT8 *) FwhInstance) + FwVolHeader->HeaderLength +
>        (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))
>      );
>
> +  //
> +  // Suppress "Value stored to ... is never read" analyzer warnings.
> +  //
> +  (VOID)FwhInstance;
> +
>    //
>    // Module type specific hook.
>    //
>    InstallVirtualAddressChangeHandler ();
>
>    PcdStatus = PcdSetBoolS (PcdOvmfFlashVariablesEnable, TRUE);
>    ASSERT_RETURN_ERROR (PcdStatus);
>    return EFI_SUCCESS;
> diff --git a/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockServiceDxe.c b/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockServiceDxe.c
> index 69b20916bc7c..979122f2e2fd 100644
> --- a/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockServiceDxe.c
> +++ b/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockServiceDxe.c
> @@ -164,16 +164,21 @@ MarkIoMemoryRangeForRuntimeAccess (
>    //
>    // Mark flash region as runtime memory
>    //
>    Status = gDS->RemoveMemorySpace (
>                    BaseAddress,
>                    Length
>                    );
>
> +  //
> +  // Suppress "Value stored to ... is never read" analyzer warnings.
> +  //
> +  (VOID)Status;
> +
>    Status = gDS->AddMemorySpace (
>                    EfiGcdMemoryTypeMemoryMappedIo,
>                    BaseAddress,
>                    Length,
>                    EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
>                    );
>    ASSERT_EFI_ERROR (Status);
>
> diff --git a/OvmfPkg/SataControllerDxe/SataController.c b/OvmfPkg/SataControllerDxe/SataController.c
> index 8d6a6bbb2286..0cf6b42c886a 100644
> --- a/OvmfPkg/SataControllerDxe/SataController.c
> +++ b/OvmfPkg/SataControllerDxe/SataController.c
> @@ -219,16 +219,21 @@ CalculateBestUdmaMode (
>    OUT UINT16            *SelectedMode
>    )
>  {
>    UINT16    TempMode;
>    UINT16    DeviceUDmaMode;
>
>    DeviceUDmaMode = 0;
>
> +  //
> +  // Suppress "Value stored to ... is never read" analyzer warnings.
> +  //
> +  (VOID)DeviceUDmaMode;
> +
>    //
>    // Check whether the WORD 88 (supported UltraDMA by drive) is valid
>    //
>    if ((IdentifyData->AtaData.field_validity & 0x04) == 0x00) {
>      return EFI_UNSUPPORTED;
>    }
>
>    DeviceUDmaMode = IdentifyData->AtaData.ultra_dma_mode;
> diff --git a/OvmfPkg/VirtioGpuDxe/Gop.c b/OvmfPkg/VirtioGpuDxe/Gop.c
> index 0b2659d1d2b9..d0f81c349f73 100644
> --- a/OvmfPkg/VirtioGpuDxe/Gop.c
> +++ b/OvmfPkg/VirtioGpuDxe/Gop.c
> @@ -57,16 +57,22 @@ ReleaseGopResources (
>      // by setting ResourceId=0 for it.
>      //
>      Status = VirtioGpuSetScanout (
>                 VgpuGop->ParentBus, // VgpuDev
>                 0, 0, 0, 0,         // X, Y, Width, Height
>                 0,                  // ScanoutId
>                 0                   // ResourceId
>                 );
> +
> +    //
> +    // Suppress "Value stored to ... is never read" analyzer warnings.
> +    //
> +    (VOID)Status;
> +
>      //
>      // HACK BEGINS HERE
>      //
>      // According to the GPU Device section of the VirtIo specification, the
>      // above operation is valid:
>      //
>      // "The driver can use resource_id = 0 to disable a scanout."
>      //
> diff --git a/OvmfPkg/VirtioNetDxe/SnpReceive.c b/OvmfPkg/VirtioNetDxe/SnpReceive.c
> index cdee9a2aee47..51b2f8a4e370 100644
> --- a/OvmfPkg/VirtioNetDxe/SnpReceive.c
> +++ b/OvmfPkg/VirtioNetDxe/SnpReceive.c
> @@ -153,16 +153,21 @@ VirtioNetReceive (
>    }
>    RxPtr += SIZE_OF_VNET (Mac);
>
>    if (Protocol != NULL) {
>      *Protocol = (UINT16) ((RxPtr[0] << 8) | RxPtr[1]);
>    }
>    RxPtr += sizeof (UINT16);
>
> +  //
> +  // Suppress "Value stored to ... is never read" analyzer warnings.
> +  //
> +  (VOID)RxPtr;
> +
>    Status = EFI_SUCCESS;
>
>  RecycleDesc:
>    ++Dev->RxLastUsed;
>
>    //
>    // virtio-0.9.5, 2.4.1 Supplying Buffers to The Device
>    //
> -- 
> 2.19.1.3.g30247aa5d201
> 
> 
> 
> 
> 

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [edk2-devel] [PATCH 02/10] MdePkg/PiFirmwareFile: fix undefined behavior in SECTION_SIZE
  2019-04-14  7:19   ` [edk2-devel] " Jordan Justen
@ 2019-04-15 16:15     ` Laszlo Ersek
  2019-04-16  8:28       ` Liming Gao
  2019-04-16  9:04       ` Jordan Justen
  0 siblings, 2 replies; 52+ messages in thread
From: Laszlo Ersek @ 2019-04-15 16:15 UTC (permalink / raw)
  To: Jordan Justen, edk2-devel-groups-io, Michael D Kinney; +Cc: Liming Gao

On 04/14/19 09:19, Jordan Justen wrote:
> On 2019-04-12 16:31:20, Laszlo Ersek wrote:
>> RH covscan justifiedly reports that accessing
>> "EFI_COMMON_SECTION_HEADER.Size", which is of type UINT8[3], through a
>> (UINT32*), is undefined behavior:
>>
>>> Error: OVERRUN (CWE-119):
>>> edk2-89910a39dcfd/OvmfPkg/Sec/SecMain.c:178: overrun-local: Overrunning
>>> array of 3 bytes at byte offset 3 by dereferencing pointer
>>> "(UINT32 *)((EFI_COMMON_SECTION_HEADER *)(UINTN)Section)->Size".
>>> #  176|       Section = (EFI_COMMON_SECTION_HEADER*)(UINTN) CurrentAddress;
>>> #  177|
>>> #  178|->     Size = SECTION_SIZE (Section);
>>> #  179|       if (Size < sizeof (*Section)) {
>>> #  180|         return EFI_VOLUME_CORRUPTED;
>>
>> Fix this by introducing EFI_COMMON_SECTION_HEADER_UNION, and expressing
>> SECTION_SIZE() in terms of "EFI_COMMON_SECTION_HEADER_UNION.Uint32".
>>
>> Cc: Liming Gao <liming.gao@intel.com>
>> Cc: Michael D Kinney <michael.d.kinney@intel.com>
>> Bugzilla: https://bugzilla.tianocore.org/show_bug.cgi?id=1710
>> Issue: scan-1007.txt
>> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
>> ---
>>  MdePkg/Include/Pi/PiFirmwareFile.h | 10 +++++++++-
>>  1 file changed, 9 insertions(+), 1 deletion(-)
>>
>> diff --git a/MdePkg/Include/Pi/PiFirmwareFile.h b/MdePkg/Include/Pi/PiFirmwareFile.h
>> index a9f3bcc4eb8e..4fce8298d1c0 100644
>> --- a/MdePkg/Include/Pi/PiFirmwareFile.h
>> +++ b/MdePkg/Include/Pi/PiFirmwareFile.h
>> @@ -229,16 +229,24 @@ typedef struct {
>>    ///
>>    UINT8             Size[3];
>>    EFI_SECTION_TYPE  Type;
>>    ///
>>    /// Declares the section type.
>>    ///
>>  } EFI_COMMON_SECTION_HEADER;
>>  
>> +///
>> +/// Union that permits accessing EFI_COMMON_SECTION_HEADER as a UINT32 object.
>> +///
>> +typedef union {
>> +  EFI_COMMON_SECTION_HEADER Hdr;
>> +  UINT32                    Uint32;
>> +} EFI_COMMON_SECTION_HEADER_UNION;
>> +
>>  typedef struct {
>>    ///
>>    /// A 24-bit unsigned integer that contains the total size of the section in bytes,
>>    /// including the EFI_COMMON_SECTION_HEADER.
>>    ///
>>    UINT8             Size[3];
>>  
>>    EFI_SECTION_TYPE  Type;
>> @@ -476,17 +484,17 @@ typedef struct {
>>    /// A UINT16 that represents a particular build. Subsequent builds have monotonically
>>    /// increasing build numbers relative to earlier builds.
>>    ///
>>    UINT16                        BuildNumber;
>>    CHAR16                        VersionString[1];
>>  } EFI_VERSION_SECTION2;
>>  
>>  #define SECTION_SIZE(SectionHeaderPtr) \
>> -    ((UINT32) (*((UINT32 *) ((EFI_COMMON_SECTION_HEADER *) (UINTN) SectionHeaderPtr)->Size) & 0x00ffffff))
>> +    (((EFI_COMMON_SECTION_HEADER_UNION *) (UINTN) (SectionHeaderPtr))->Uint32 & 0x00ffffff)
> 
> Mike, all,
> 
> Can we add a typedef for EFI_COMMON_SECTION_HEADER_UNION if it's not
> in the PI spec?
> 
> If it's not allowed, I think something like this might work too:
> 
> #define SECTION_SIZE(SectionHeaderPtr) \
>     (*((UINT32*)(UINTN)(SectionHeaderPtr)) & 0x00ffffff)

(Less importantly:)

It might shut up the static analyzer, but regarding the C standard, it's
equally undefined behavior.

Anyway I don't feel too strongly about this, given that we disable the
strict aliasing / effective type rules in "tools_def.template"
("-fno-strict-aliasing").

> Then again, I see SECTION_SIZE is not in the spec, so maybe it's ok to
> add the typedef.

(More importantly:)

Indeed the doubt you voice about ..._UNION crossed my mind, but then I
too searched the PI spec for SECTION_SIZE, with no hits.

Beyond that, I searched both the PI and UEFI specs, for "_UNION" --
again no hits, despite our definitions of:

- EFI_IMAGE_OPTIONAL_HEADER_UNION
- EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION

in

- "MdePkg/Include/IndustryStandard/PeImage.h"
- "MdePkg/Include/Protocol/GraphicsOutput.h"

respectively.

Thanks,
Laszlo

> 
> -Jordan
> 


^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH 00/10] patches for some warnings raised by "RH covscan"
  2019-04-12 23:36 ` [PATCH 00/10] patches for some warnings raised by "RH covscan" Ard Biesheuvel
@ 2019-04-15 16:16   ` Laszlo Ersek
  0 siblings, 0 replies; 52+ messages in thread
From: Laszlo Ersek @ 2019-04-15 16:16 UTC (permalink / raw)
  To: Ard Biesheuvel
  Cc: edk2-devel-groups-io, Anthony Perard, Bob Feng, Jordan Justen,
	Julien Grall, Liming Gao, Michael D Kinney, Yonghong Zhu

On 04/13/19 01:36, Ard Biesheuvel wrote:
> On Fri, 12 Apr 2019 at 16:31, Laszlo Ersek <lersek@redhat.com> wrote:
>>
>> Bugzilla: https://bugzilla.tianocore.org/show_bug.cgi?id=1710
>> Repo:     https://github.com/lersek/edk2.git
>> Branch:   covscan_bz_1710
>>
>> "covscan" is an internal service at Red Hat that lets associates run
>> static analysis tools on Fedora/RHEL packages. It drives a number of
>> static analyzers.
>>
>> While covscan's existence is not "secret" (if you google it, you get a
>> bunch of hits in the Red Hat Bugzilla), I can *not* use or offer covscan
>> as a general upstream tool; for that the TianoCore community will have
>> to build its own service / environment.
>>
>> Anyway, "covscan" happened to drop a bunch of reports on me for...
>> "reasons", and so I turned a short 10 hour workday into yet anoher
>> normal 15 hour workday (stealing some free time whence there was none)
>> in order to do something, up-stream, about the warnings that affected
>> OvmfPkg. No claim is made about the completeness of the scan's coverage.
>>
>> Some of the patches seek to suppress warnings, some strive to remedy
>> valid-looking issues. We should not spend much time on this series.
>>
>> Cc: Anthony Perard <anthony.perard@citrix.com>
>> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
>> Cc: Bob Feng <bob.c.feng@intel.com>
>> Cc: Jordan Justen <jordan.l.justen@intel.com>
>> Cc: Julien Grall <julien.grall@arm.com>
>> Cc: Liming Gao <liming.gao@intel.com>
>> Cc: Michael D Kinney <michael.d.kinney@intel.com>
>> Cc: Yonghong Zhu <yonghong.zhu@intel.com>
>>
>> Thanks
>> Laszlo
>>
>> Laszlo Ersek (10):
>>   MdePkg/PiFirmwareFile: express IS_SECTION2 in terms of SECTION_SIZE
>>   MdePkg/PiFirmwareFile: fix undefined behavior in SECTION_SIZE
>>   BaseTools/PiFirmwareFile: fix undefined behavior in SECTION_SIZE
>>   MdePkg/PiFirmwareFile: fix undefined behavior in FFS_FILE_SIZE
>>   OvmfPkg/Sec: fix out-of-bounds reads
>>   OvmfPkg/QemuVideoDxe: avoid arithmetic on null pointer
>>   OvmfPkg/AcpiPlatformDxe: suppress invalid "deref of undef pointer"
>>     warning
>>   OvmfPkg: suppress "Value stored to ... is never read" analyzer
>>     warnings
>>   OvmfPkg/AcpiPlatformDxe: catch theoretical nullptr deref in Xen code
>>   OvmfPkg/BasePciCapLib: suppress invalid "nullptr deref" warning
>>
> 
> Thanks for the cleanup. I wasn't cc'ed on all patches,

Sorry about that, it wasn't trivial to figure out whom to CC on what,
and I opted for sticking with Maintainers.txt (AFAIR).

> but this looks good afaict.
> 
> Where needed,
> 
> Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

Thanks!
Laszlo

> 
> 
>>  BaseTools/Source/C/Include/Common/PiFirmwareFile.h            |  7 +++++-
>>  MdePkg/Include/Pi/PiFirmwareFile.h                            | 26 ++++++++++++++++----
>>  OvmfPkg/AcpiPlatformDxe/AcpiPlatform.c                        |  7 ++++++
>>  OvmfPkg/AcpiPlatformDxe/Xen.c                                 | 14 ++++++++++-
>>  OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c                 |  7 ++++++
>>  OvmfPkg/Library/PlatformBootManagerLib/QemuKernel.c           |  5 ++++
>>  OvmfPkg/Library/SerializeVariablesLib/SerializeVariablesLib.c |  4 +++
>>  OvmfPkg/Library/VirtioLib/VirtioLib.c                         |  5 ++++
>>  OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c       |  5 ++++
>>  OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockServiceDxe.c    |  5 ++++
>>  OvmfPkg/QemuVideoDxe/VbeShim.c                                |  2 +-
>>  OvmfPkg/SataControllerDxe/SataController.c                    |  5 ++++
>>  OvmfPkg/Sec/SecMain.c                                         |  6 ++---
>>  OvmfPkg/VirtioGpuDxe/Gop.c                                    |  6 +++++
>>  OvmfPkg/VirtioNetDxe/SnpReceive.c                             |  5 ++++
>>  15 files changed, 98 insertions(+), 11 deletions(-)
>>
>> --
>> 2.19.1.3.g30247aa5d201
>>


^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [edk2-devel] [PATCH 08/10] OvmfPkg: suppress "Value stored to ... is never read" analyzer warnings
  2019-04-14  8:03   ` [edk2-devel] " Jordan Justen
@ 2019-04-15 16:25     ` Laszlo Ersek
  2019-04-16  9:26       ` Jordan Justen
  0 siblings, 1 reply; 52+ messages in thread
From: Laszlo Ersek @ 2019-04-15 16:25 UTC (permalink / raw)
  To: Jordan Justen, edk2-devel-groups-io
  Cc: Anthony Perard, Ard Biesheuvel, Julien Grall

On 04/14/19 10:03, Jordan Justen wrote:
> On 2019-04-12 16:31:26, Laszlo Ersek wrote:
>> RH covscan warns about assignments that it can determine are never
>> "consumed" later ("dead stores"). The idea behind the warning is
>> presumably that the programmer forgot to implement a dependent check
>> somewhere.
>>
>> For each such warning that has been emitted for OvmfPkg,
>> the case is one of the following however:
>>
>> - We assign a variable a value for (re-)initialization's sake, in
>>   preparation for further or future uses. This practice is safe (sometimes
>>   even recommended!), hence we should suppress these warnings.
>>
>> - We capture a result or a computation in a variable, following a general
>>   programming pattern, but then decide to ignore the value in that
>>   particular case. This is again safe, and we should suppress these
>>   warnings too.
>>
>> According to the Clang documentation at
>>
>>   https://clang-analyzer.llvm.org/faq.html#dead_store
>>
>> we should use
>>
>>   (void)x;
>>
>> See the logs below (produced originally for edk2-stable201903).
>>
>>> Error: CLANG_WARNING:
>>> edk2-89910a39dcfd/OvmfPkg/AcpiPlatformDxe/Xen.c:156:3: warning: Value
>>> stored to 'NumberOfTableEntries' is never read
>>> #  NumberOfTableEntries = 0;
>>> #  ^                      ~
>>> edk2-89910a39dcfd/OvmfPkg/AcpiPlatformDxe/Xen.c:156:3: note: Value
>>> stored to 'NumberOfTableEntries' is never read
>>> #  NumberOfTableEntries = 0;
>>> #  ^                      ~
>>> #  154|     DsdtTable   = NULL;
>>> #  155|     TableHandle = 0;
>>> #  156|->   NumberOfTableEntries = 0;
>>> #  157|
>>> #  158|     //
>>>
>>> Error: CLANG_WARNING:
>>> edk2-89910a39dcfd/OvmfPkg/Library/PlatformBootManagerLib/QemuKernel.c:43:3:
>>> warning: Value stored to 'SetupSize' is never read
>>> #  SetupSize = 0;
>>> #  ^           ~
>>> edk2-89910a39dcfd/OvmfPkg/Library/PlatformBootManagerLib/QemuKernel.c:43:3:
>>> note: Value stored to 'SetupSize' is never read
>>> #  SetupSize = 0;
>>> #  ^           ~
>>> #   41|
>>> #   42|     SetupBuf = NULL;
>>> #   43|->   SetupSize = 0;
>>> #   44|     KernelBuf = NULL;
>>> #   45|     KernelInitialSize = 0;
>>>
>>> Error: CLANG_WARNING:
>>> edk2-89910a39dcfd/OvmfPkg/Library/SerializeVariablesLib/SerializeVariablesLib.c:609:9:
>>> warning: Value stored to 'VariableDataBufferSize' is never read
>>> #        VariableDataBufferSize = 0;
>>> #        ^                        ~
>>> edk2-89910a39dcfd/OvmfPkg/Library/SerializeVariablesLib/SerializeVariablesLib.c:609:9:
>>> note: Value stored to 'VariableDataBufferSize' is never read
>>> #        VariableDataBufferSize = 0;
>>> #        ^                        ~
>>> #  607|           FreePool (VariableData);
>>> #  608|           VariableData = NULL;
>>> #  609|->         VariableDataBufferSize = 0;
>>> #  610|         }
>>> #  611|         VariableData = AllocatePool (VariableDataSize);
>>>
>>> Error: CLANG_WARNING:
>>> edk2-89910a39dcfd/OvmfPkg/Library/VirtioLib/VirtioLib.c:125:3: warning:
>>> Value stored to 'RingPagesPtr' is never read
>>> #  RingPagesPtr += sizeof *Ring->Used.AvailEvent;
>>> #  ^               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>> edk2-89910a39dcfd/OvmfPkg/Library/VirtioLib/VirtioLib.c:125:3: note:
>>> Value stored to 'RingPagesPtr' is never read
>>> #  RingPagesPtr += sizeof *Ring->Used.AvailEvent;
>>> #  ^               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>> #  123|
>>> #  124|     Ring->Used.AvailEvent = (volatile VOID *) RingPagesPtr;
>>> #  125|->   RingPagesPtr += sizeof *Ring->Used.AvailEvent;
>>> #  126|
>>> #  127|     Ring->QueueSize = QueueSize;
>>>
>>> Error: CLANG_WARNING:
>>> edk2-89910a39dcfd/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c:1079:3:
>>> warning: Value stored to 'FwhInstance' is never read
>>> #  FwhInstance = (EFI_FW_VOL_INSTANCE *)
>>> #  ^             ~~~~~~~~~~~~~~~~~~~~~~~
>>> edk2-89910a39dcfd/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c:1079:3:
>>> note: Value stored to 'FwhInstance' is never read
>>> #  FwhInstance = (EFI_FW_VOL_INSTANCE *)
>>> #  ^             ~~~~~~~~~~~~~~~~~~~~~~~
>>> # 1077|     ASSERT_RETURN_ERROR (PcdStatus);
>>> # 1078|
>>> # 1079|->   FwhInstance = (EFI_FW_VOL_INSTANCE *)
>>> # 1080|       (
>>> # 1081|         (UINTN) ((UINT8 *) FwhInstance) + FwVolHeader->HeaderLength +
>>>
>>> Error: CLANG_WARNING:
>>> edk2-89910a39dcfd/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockServiceDxe.c:173:3:
>>> warning: Value stored to 'Status' is never read
>>> #  Status = gDS->RemoveMemorySpace (
>>> #  ^        ~~~~~~~~~~~~~~~~~~~~~~~~
>>> edk2-89910a39dcfd/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockServiceDxe.c:173:3:
>>> note: Value stored to 'Status' is never read
>>> #  Status = gDS->RemoveMemorySpace (
>>> #  ^        ~~~~~~~~~~~~~~~~~~~~~~~~
>>> #  171|     // Mark flash region as runtime memory
>>> #  172|     //
>>> #  173|->   Status = gDS->RemoveMemorySpace (
>>> #  174|                     BaseAddress,
>>> #  175|                     Length
>>>
>>> Error: CLANG_WARNING:
>>> edk2-89910a39dcfd/OvmfPkg/SataControllerDxe/SataController.c:231:3:
>>> warning: Value stored to 'DeviceUDmaMode' is never read
>>> #  DeviceUDmaMode = 0;
>>> #  ^                ~
>>> edk2-89910a39dcfd/OvmfPkg/SataControllerDxe/SataController.c:231:3:
>>> note: Value stored to 'DeviceUDmaMode' is never read
>>> #  DeviceUDmaMode = 0;
>>> #  ^                ~
>>> #  229|     UINT16    DeviceUDmaMode;
>>> #  230|
>>> #  231|->   DeviceUDmaMode = 0;
>>> #  232|
>>> #  233|     //
>>>
>>> Error: CLANG_WARNING:
>>> edk2-89910a39dcfd/OvmfPkg/VirtioGpuDxe/Gop.c:65:5: warning: Value stored
>>> to 'Status' is never read
>>> #    Status = VirtioGpuSetScanout (
>>> #    ^        ~~~~~~~~~~~~~~~~~~~~~
>>> edk2-89910a39dcfd/OvmfPkg/VirtioGpuDxe/Gop.c:65:5: note: Value stored to
>>> 'Status' is never read
>>> #    Status = VirtioGpuSetScanout (
>>> #    ^        ~~~~~~~~~~~~~~~~~~~~~
>>> #   63|       // by setting ResourceId=0 for it.
>>> #   64|       //
>>> #   65|->     Status = VirtioGpuSetScanout (
>>> #   66|                  VgpuGop->ParentBus, // VgpuDev
>>> #   67|                  0, 0, 0, 0,         // X, Y, Width, Height
>>>
>>> Error: CLANG_WARNING:
>>> edk2-89910a39dcfd/OvmfPkg/VirtioNetDxe/SnpReceive.c:165:3: warning:
>>> Value stored to 'RxPtr' is never read
>>> #  RxPtr += sizeof (UINT16);
>>> #  ^        ~~~~~~~~~~~~~~~
>>> edk2-89910a39dcfd/OvmfPkg/VirtioNetDxe/SnpReceive.c:165:3: note: Value
>>> stored to 'RxPtr' is never read
>>> #  RxPtr += sizeof (UINT16);
>>> #  ^        ~~~~~~~~~~~~~~~
>>> #  163|       *Protocol = (UINT16) ((RxPtr[0] << 8) | RxPtr[1]);
>>> #  164|     }
>>> #  165|->   RxPtr += sizeof (UINT16);
>>> #  166|
>>> #  167|     Status = EFI_SUCCESS;
>>
>> Cc: Anthony Perard <anthony.perard@citrix.com>
>> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
>> Cc: Jordan Justen <jordan.l.justen@intel.com>
>> Cc: Julien Grall <julien.grall@arm.com>
>> Bugzilla: https://bugzilla.tianocore.org/show_bug.cgi?id=1710
>> Issue: scan-0992.txt
>> Issue: scan-0996.txt
>> Issue: scan-0997.txt
>> Issue: scan-0998.txt
>> Issue: scan-1000.txt
>> Issue: scan-1001.txt
>> Issue: scan-1006.txt
>> Issue: scan-1011.txt
>> Issue: scan-1012.txt
>> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
>> ---
>>  OvmfPkg/AcpiPlatformDxe/Xen.c                                 | 5 +++++
>>  OvmfPkg/Library/PlatformBootManagerLib/QemuKernel.c           | 5 +++++
>>  OvmfPkg/Library/SerializeVariablesLib/SerializeVariablesLib.c | 4 ++++
>>  OvmfPkg/Library/VirtioLib/VirtioLib.c                         | 5 +++++
>>  OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c       | 5 +++++
>>  OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockServiceDxe.c    | 5 +++++
>>  OvmfPkg/SataControllerDxe/SataController.c                    | 5 +++++
>>  OvmfPkg/VirtioGpuDxe/Gop.c                                    | 6 ++++++
>>  OvmfPkg/VirtioNetDxe/SnpReceive.c                             | 5 +++++
>>  9 files changed, 45 insertions(+)
>>
>> diff --git a/OvmfPkg/AcpiPlatformDxe/Xen.c b/OvmfPkg/AcpiPlatformDxe/Xen.c
>> index 357c60d23f4e..c8f275a8ee84 100644
>> --- a/OvmfPkg/AcpiPlatformDxe/Xen.c
>> +++ b/OvmfPkg/AcpiPlatformDxe/Xen.c
>> @@ -144,16 +144,21 @@ InstallXenTables (
>>    Fadt2Table  = NULL;
>>    Fadt1Table  = NULL;
>>    Facs2Table  = NULL;
>>    Facs1Table  = NULL;
>>    DsdtTable   = NULL;
>>    TableHandle = 0;
>>    NumberOfTableEntries = 0;
>>  
>> +  //
>> +  // Suppress "Value stored to ... is never read" analyzer warnings.
>> +  //
>> +  (VOID)NumberOfTableEntries;
>> +
> 
> I've seen this solution to shut up the compiler for similar reasons,
> and it kind of bugs me.
> 
> It looks like both paths of the if & else initialize
> NumberOfTableEntries, so maybe we can just drop setting it to 0?

It might trigger *other* compilers to whine about "variable read without
initialization" :)

> I looked at FwhInstance too, and it doesn't look like it is used after
> being set. So, maybe that should just be dropped?
> 
> I guess both of your bullet points give arguments allowing the unused
> set.
> 
> Rather than adding "Suppress..." comments everywhere, maybe a global
> macro could be defined for similar uses in EDK II?
> 
> //
> // Suppress "Value stored to ... is never read" analyzer warnings.
> //
> #define IGNORE_UNUSED_ASSIGNMENT(var) ((VOID)var)
> 
> Then again, I guess we decided to suppress this in EDK II compiler
> warnings with -Wno-unused-but-set-variable.
> 
> So, can you adjust the RH covscan tool settings to similarly ignore
> these warnings?

I think that should be possible, yes. AIUI it is supposed to have
location-sensitive permanent overrides (maintained outside of the source
code), and it should be doing incremental / differential scanning --
report only "new" issues.

Admittedly, I hate most of the warning suppression patches myself,
littering our code -- and that applies to all the *historical* spurious
assignments that we already have in place --, so I'm 100% fine with
dropping this patch (and other suppression patches too, if that is the
upstream edk2 project's preference!)

Thanks!
Laszlo



>>    //
>>    // Try to find Xen ACPI tables
>>    //
>>    Status = GetXenAcpiRsdp (&XenAcpiRsdpStructurePtr);
>>    if (EFI_ERROR (Status)) {
>>      return Status;
>>    }
>>  
>> diff --git a/OvmfPkg/Library/PlatformBootManagerLib/QemuKernel.c b/OvmfPkg/Library/PlatformBootManagerLib/QemuKernel.c
>> index ddfef925edd3..fde8c40218a4 100644
>> --- a/OvmfPkg/Library/PlatformBootManagerLib/QemuKernel.c
>> +++ b/OvmfPkg/Library/PlatformBootManagerLib/QemuKernel.c
>> @@ -37,16 +37,21 @@ TryRunningQemuKernel (
>>    SetupSize = 0;
>>    KernelBuf = NULL;
>>    KernelInitialSize = 0;
>>    CommandLine = NULL;
>>    CommandLineSize = 0;
>>    InitrdData = NULL;
>>    InitrdSize = 0;
>>  
>> +  //
>> +  // Suppress "Value stored to ... is never read" analyzer warnings.
>> +  //
>> +  (VOID)SetupSize;
>> +
>>    if (!QemuFwCfgIsAvailable ()) {
>>      return EFI_NOT_FOUND;
>>    }
>>  
>>    QemuFwCfgSelectItem (QemuFwCfgItemKernelSize);
>>    KernelSize = (UINTN) QemuFwCfgRead64 ();
>>  
>>    QemuFwCfgSelectItem (QemuFwCfgItemKernelSetupSize);
>> diff --git a/OvmfPkg/Library/SerializeVariablesLib/SerializeVariablesLib.c b/OvmfPkg/Library/SerializeVariablesLib/SerializeVariablesLib.c
>> index a6cebcb54f6b..64fe9d9be543 100644
>> --- a/OvmfPkg/Library/SerializeVariablesLib/SerializeVariablesLib.c
>> +++ b/OvmfPkg/Library/SerializeVariablesLib/SerializeVariablesLib.c
>> @@ -596,16 +596,20 @@ SerializeVariablesIterateSystemVariables (
>>        //
>>        // The currently allocated VariableData buffer is too small,
>>        // so we allocate a larger buffer.
>>        //
>>        if (VariableDataBufferSize != 0) {
>>          FreePool (VariableData);
>>          VariableData = NULL;
>>          VariableDataBufferSize = 0;
>> +        //
>> +        // Suppress "Value stored to ... is never read" analyzer warnings.
>> +        //
>> +        (VOID)VariableDataBufferSize;
>>        }
>>        VariableData = AllocatePool (VariableDataSize);
>>        if (VariableData == NULL) {
>>          Status = EFI_OUT_OF_RESOURCES;
>>          break;
>>        }
>>        VariableDataBufferSize = VariableDataSize;
>>  
>> diff --git a/OvmfPkg/Library/VirtioLib/VirtioLib.c b/OvmfPkg/Library/VirtioLib/VirtioLib.c
>> index 555d2a5ce7c9..0e4b8b6b265e 100644
>> --- a/OvmfPkg/Library/VirtioLib/VirtioLib.c
>> +++ b/OvmfPkg/Library/VirtioLib/VirtioLib.c
>> @@ -113,16 +113,21 @@ VirtioRingInit (
>>    RingPagesPtr += sizeof *Ring->Used.Idx;
>>  
>>    Ring->Used.UsedElem = (volatile VOID *) RingPagesPtr;
>>    RingPagesPtr += sizeof *Ring->Used.UsedElem * QueueSize;
>>  
>>    Ring->Used.AvailEvent = (volatile VOID *) RingPagesPtr;
>>    RingPagesPtr += sizeof *Ring->Used.AvailEvent;
>>  
>> +  //
>> +  // Suppress "Value stored to ... is never read" analyzer warnings.
>> +  //
>> +  (VOID)RingPagesPtr;
>> +
>>    Ring->QueueSize = QueueSize;
>>    return EFI_SUCCESS;
>>  }
>>  
>>  
>>  /**
>>  
>>    Tear down the internal resources of a configured virtio ring.
>> diff --git a/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c b/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c
>> index edf438a422fa..ff6565865846 100644
>> --- a/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c
>> +++ b/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c
>> @@ -1071,16 +1071,21 @@ FvbInitialize (
>>    ASSERT_RETURN_ERROR (PcdStatus);
>>  
>>    FwhInstance = (EFI_FW_VOL_INSTANCE *)
>>      (
>>        (UINTN) ((UINT8 *) FwhInstance) + FwVolHeader->HeaderLength +
>>        (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))
>>      );
>>  
>> +  //
>> +  // Suppress "Value stored to ... is never read" analyzer warnings.
>> +  //
>> +  (VOID)FwhInstance;
>> +
>>    //
>>    // Module type specific hook.
>>    //
>>    InstallVirtualAddressChangeHandler ();
>>  
>>    PcdStatus = PcdSetBoolS (PcdOvmfFlashVariablesEnable, TRUE);
>>    ASSERT_RETURN_ERROR (PcdStatus);
>>    return EFI_SUCCESS;
>> diff --git a/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockServiceDxe.c b/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockServiceDxe.c
>> index 69b20916bc7c..979122f2e2fd 100644
>> --- a/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockServiceDxe.c
>> +++ b/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockServiceDxe.c
>> @@ -164,16 +164,21 @@ MarkIoMemoryRangeForRuntimeAccess (
>>    //
>>    // Mark flash region as runtime memory
>>    //
>>    Status = gDS->RemoveMemorySpace (
>>                    BaseAddress,
>>                    Length
>>                    );
>>  
>> +  //
>> +  // Suppress "Value stored to ... is never read" analyzer warnings.
>> +  //
>> +  (VOID)Status;
>> +
>>    Status = gDS->AddMemorySpace (
>>                    EfiGcdMemoryTypeMemoryMappedIo,
>>                    BaseAddress,
>>                    Length,
>>                    EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
>>                    );
>>    ASSERT_EFI_ERROR (Status);
>>  
>> diff --git a/OvmfPkg/SataControllerDxe/SataController.c b/OvmfPkg/SataControllerDxe/SataController.c
>> index 8d6a6bbb2286..0cf6b42c886a 100644
>> --- a/OvmfPkg/SataControllerDxe/SataController.c
>> +++ b/OvmfPkg/SataControllerDxe/SataController.c
>> @@ -219,16 +219,21 @@ CalculateBestUdmaMode (
>>    OUT UINT16            *SelectedMode
>>    )
>>  {
>>    UINT16    TempMode;
>>    UINT16    DeviceUDmaMode;
>>  
>>    DeviceUDmaMode = 0;
>>  
>> +  //
>> +  // Suppress "Value stored to ... is never read" analyzer warnings.
>> +  //
>> +  (VOID)DeviceUDmaMode;
>> +
>>    //
>>    // Check whether the WORD 88 (supported UltraDMA by drive) is valid
>>    //
>>    if ((IdentifyData->AtaData.field_validity & 0x04) == 0x00) {
>>      return EFI_UNSUPPORTED;
>>    }
>>  
>>    DeviceUDmaMode = IdentifyData->AtaData.ultra_dma_mode;
>> diff --git a/OvmfPkg/VirtioGpuDxe/Gop.c b/OvmfPkg/VirtioGpuDxe/Gop.c
>> index 0b2659d1d2b9..d0f81c349f73 100644
>> --- a/OvmfPkg/VirtioGpuDxe/Gop.c
>> +++ b/OvmfPkg/VirtioGpuDxe/Gop.c
>> @@ -57,16 +57,22 @@ ReleaseGopResources (
>>      // by setting ResourceId=0 for it.
>>      //
>>      Status = VirtioGpuSetScanout (
>>                 VgpuGop->ParentBus, // VgpuDev
>>                 0, 0, 0, 0,         // X, Y, Width, Height
>>                 0,                  // ScanoutId
>>                 0                   // ResourceId
>>                 );
>> +
>> +    //
>> +    // Suppress "Value stored to ... is never read" analyzer warnings.
>> +    //
>> +    (VOID)Status;
>> +
>>      //
>>      // HACK BEGINS HERE
>>      //
>>      // According to the GPU Device section of the VirtIo specification, the
>>      // above operation is valid:
>>      //
>>      // "The driver can use resource_id = 0 to disable a scanout."
>>      //
>> diff --git a/OvmfPkg/VirtioNetDxe/SnpReceive.c b/OvmfPkg/VirtioNetDxe/SnpReceive.c
>> index cdee9a2aee47..51b2f8a4e370 100644
>> --- a/OvmfPkg/VirtioNetDxe/SnpReceive.c
>> +++ b/OvmfPkg/VirtioNetDxe/SnpReceive.c
>> @@ -153,16 +153,21 @@ VirtioNetReceive (
>>    }
>>    RxPtr += SIZE_OF_VNET (Mac);
>>  
>>    if (Protocol != NULL) {
>>      *Protocol = (UINT16) ((RxPtr[0] << 8) | RxPtr[1]);
>>    }
>>    RxPtr += sizeof (UINT16);
>>  
>> +  //
>> +  // Suppress "Value stored to ... is never read" analyzer warnings.
>> +  //
>> +  (VOID)RxPtr;
>> +
>>    Status = EFI_SUCCESS;
>>  
>>  RecycleDesc:
>>    ++Dev->RxLastUsed;
>>  
>>    //
>>    // virtio-0.9.5, 2.4.1 Supplying Buffers to The Device
>>    //
>> -- 
>> 2.19.1.3.g30247aa5d201
>>
>>
>>
>> 
>>


^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [edk2-devel] [PATCH 01/10] MdePkg/PiFirmwareFile: express IS_SECTION2 in terms of SECTION_SIZE
  2019-04-12 23:31 ` [PATCH 01/10] MdePkg/PiFirmwareFile: express IS_SECTION2 in terms of SECTION_SIZE Laszlo Ersek
@ 2019-04-15 17:01   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 52+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-04-15 17:01 UTC (permalink / raw)
  To: devel, lersek; +Cc: Liming Gao, Michael D Kinney

On 4/13/19 1:31 AM, Laszlo Ersek wrote:
> The IS_SECTION2() function-like macro duplicates the SECTION_SIZE()
> calculation, just to compare the computed size against 0xFFFFFF. Invoke
> SECTION_SIZE() instead; only preserve the comparison.
> 
> Cc: Liming Gao <liming.gao@intel.com>
> Cc: Michael D Kinney <michael.d.kinney@intel.com>
> Bugzilla: https://bugzilla.tianocore.org/show_bug.cgi?id=1710
> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> ---
>  MdePkg/Include/Pi/PiFirmwareFile.h | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/MdePkg/Include/Pi/PiFirmwareFile.h b/MdePkg/Include/Pi/PiFirmwareFile.h
> index 56efabcba3ec..a9f3bcc4eb8e 100644
> --- a/MdePkg/Include/Pi/PiFirmwareFile.h
> +++ b/MdePkg/Include/Pi/PiFirmwareFile.h
> @@ -475,21 +475,21 @@ typedef struct {
>    ///
>    /// A UINT16 that represents a particular build. Subsequent builds have monotonically
>    /// increasing build numbers relative to earlier builds.
>    ///
>    UINT16                        BuildNumber;
>    CHAR16                        VersionString[1];
>  } EFI_VERSION_SECTION2;
>  
> -#define IS_SECTION2(SectionHeaderPtr) \
> -    ((UINT32) (*((UINT32 *) ((EFI_COMMON_SECTION_HEADER *) (UINTN) SectionHeaderPtr)->Size) & 0x00ffffff) == 0x00ffffff)
> -
>  #define SECTION_SIZE(SectionHeaderPtr) \
>      ((UINT32) (*((UINT32 *) ((EFI_COMMON_SECTION_HEADER *) (UINTN) SectionHeaderPtr)->Size) & 0x00ffffff))
>  
> +#define IS_SECTION2(SectionHeaderPtr) \
> +    (SECTION_SIZE (SectionHeaderPtr) == 0x00ffffff)
> +
>  #define SECTION2_SIZE(SectionHeaderPtr) \
>      (((EFI_COMMON_SECTION_HEADER2 *) (UINTN) SectionHeaderPtr)->ExtendedSize)
>  
>  #pragma pack()
>  
>  #endif
>  
> 

Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [edk2-devel] [PATCH 04/10] MdePkg/PiFirmwareFile: fix undefined behavior in FFS_FILE_SIZE
  2019-04-12 23:31 ` [PATCH 04/10] MdePkg/PiFirmwareFile: fix undefined behavior in FFS_FILE_SIZE Laszlo Ersek
@ 2019-04-15 17:23   ` Philippe Mathieu-Daudé
  2019-04-17 17:52   ` Michael D Kinney
  1 sibling, 0 replies; 52+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-04-15 17:23 UTC (permalink / raw)
  To: devel, lersek; +Cc: Liming Gao, Michael D Kinney

On 4/13/19 1:31 AM, Laszlo Ersek wrote:
> Accessing "EFI_FFS_FILE_HEADER.Size", which is of type UINT8[3], through a
> (UINT32*), is undefined behavior. Fix it by accessing the array elements
> individually.
> 
> (We can't use a union here, unfortunately, as easily as with
> "EFI_COMMON_SECTION_HEADER", given the fields in "EFI_FFS_FILE_HEADER".)
> 
> Cc: Liming Gao <liming.gao@intel.com>
> Cc: Michael D Kinney <michael.d.kinney@intel.com>
> Bugzilla: https://bugzilla.tianocore.org/show_bug.cgi?id=1710
> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> ---
>  MdePkg/Include/Pi/PiFirmwareFile.h | 10 +++++++++-
>  1 file changed, 9 insertions(+), 1 deletion(-)
> 
> diff --git a/MdePkg/Include/Pi/PiFirmwareFile.h b/MdePkg/Include/Pi/PiFirmwareFile.h
> index 4fce8298d1c0..0668f3fa9af4 100644
> --- a/MdePkg/Include/Pi/PiFirmwareFile.h
> +++ b/MdePkg/Include/Pi/PiFirmwareFile.h
> @@ -174,18 +174,26 @@ typedef struct {
>    /// If FFS_ATTRIB_LARGE_FILE is not set then EFI_FFS_FILE_HEADER is used.
>    ///
>    UINT64                    ExtendedSize;
>  } EFI_FFS_FILE_HEADER2;
>  
>  #define IS_FFS_FILE2(FfsFileHeaderPtr) \
>      (((((EFI_FFS_FILE_HEADER *) (UINTN) FfsFileHeaderPtr)->Attributes) & FFS_ATTRIB_LARGE_FILE) == FFS_ATTRIB_LARGE_FILE)
>  
> +#define FFS_FILE_SIZE_ARRAY(FfsFileHeaderPtr) \
> +    (((EFI_FFS_FILE_HEADER *) (UINTN) (FfsFileHeaderPtr))->Size)
> +
> +#define FFS_FILE_SIZE_ELEMENT(FfsFileHeaderPtr, Index) \
> +    ((UINT32) FFS_FILE_SIZE_ARRAY (FfsFileHeaderPtr)[(Index)])
> +
>  #define FFS_FILE_SIZE(FfsFileHeaderPtr) \
> -    ((UINT32) (*((UINT32 *) ((EFI_FFS_FILE_HEADER *) (UINTN) FfsFileHeaderPtr)->Size) & 0x00ffffff))
> +    ((FFS_FILE_SIZE_ELEMENT ((FfsFileHeaderPtr), 0) <<  0) | \
> +     (FFS_FILE_SIZE_ELEMENT ((FfsFileHeaderPtr), 1) <<  8) | \
> +     (FFS_FILE_SIZE_ELEMENT ((FfsFileHeaderPtr), 2) << 16))
>  
>  #define FFS_FILE2_SIZE(FfsFileHeaderPtr) \
>      ((UINT32) (((EFI_FFS_FILE_HEADER2 *) (UINTN) FfsFileHeaderPtr)->ExtendedSize))
>  
>  typedef UINT8 EFI_SECTION_TYPE;
>  
>  ///
>  /// Pseudo type. It is used as a wild card when retrieving sections.
> 

Reviewed-by: Philippe Mathieu-Daude <philmd@redhat.com>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [edk2-devel] [PATCH 05/10] OvmfPkg/Sec: fix out-of-bounds reads
  2019-04-12 23:31 ` [PATCH 05/10] OvmfPkg/Sec: fix out-of-bounds reads Laszlo Ersek
@ 2019-04-15 17:24   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 52+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-04-15 17:24 UTC (permalink / raw)
  To: devel, lersek; +Cc: Ard Biesheuvel, Jordan Justen

On 4/13/19 1:31 AM, Laszlo Ersek wrote:
> RH covscan justifiedly reports that accessing "EFI_FFS_FILE_HEADER.Size"
> and "EFI_COMMON_SECTION_HEADER.Size", which both are of type UINT8[3],
> through (UINT32*), is undefined behavior:
> 
>> Error: OVERRUN (CWE-119):
>> edk2-89910a39dcfd/OvmfPkg/Sec/SecMain.c:283: overrun-local: Overrunning
>> array of 3 bytes at byte offset 3 by dereferencing pointer
>> "(UINT32 *)File->Size".
>> #  281|
>> #  282|       File = (EFI_FFS_FILE_HEADER*)(UINTN) CurrentAddress;
>> #  283|->     Size = *(UINT32*) File->Size & 0xffffff;
>> #  284|       if (Size < (sizeof (*File) + sizeof (EFI_COMMON_SECTION_HEADER))) {
>> #  285|         return EFI_VOLUME_CORRUPTED;
>>
>> Error: OVERRUN (CWE-119):
>> edk2-89910a39dcfd/OvmfPkg/Sec/SecMain.c:614: overrun-local: Overrunning
>> array of 3 bytes at byte offset 3 by dereferencing pointer
>> "(UINT32 *)File->Size".
>> #  612|
>> #  613|       File = (EFI_FFS_FILE_HEADER*)(UINTN) CurrentAddress;
>> #  614|->     Size = *(UINT32*) File->Size & 0xffffff;
>> #  615|       if (Size < sizeof (*File)) {
>> #  616|         return EFI_NOT_FOUND;
>>
>> Error: OVERRUN (CWE-119):
>> edk2-89910a39dcfd/OvmfPkg/Sec/SecMain.c:639: overrun-local: Overrunning
>> array of 3 bytes at byte offset 3 by dereferencing pointer
>> "(UINT32 *)Section->Size".
>> #  637|         Section = (EFI_COMMON_SECTION_HEADER*)(UINTN) CurrentAddress;
>> #  638|
>> #  639|->       Size = *(UINT32*) Section->Size & 0xffffff;
>> #  640|         if (Size < sizeof (*Section)) {
>> #  641|           return EFI_NOT_FOUND;
> 
> Fix these by invoking the FFS_FILE_SIZE() and SECTION_SIZE() macros, which
> by now have been fixed too.
> 
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Bugzilla: https://bugzilla.tianocore.org/show_bug.cgi?id=1710
> Issue: scan-1008.txt
> Issue: scan-1009.txt
> Issue: scan-1010.txt
> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> ---
>  OvmfPkg/Sec/SecMain.c | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/OvmfPkg/Sec/SecMain.c b/OvmfPkg/Sec/SecMain.c
> index 18a89c649fd4..3914355cd17b 100644
> --- a/OvmfPkg/Sec/SecMain.c
> +++ b/OvmfPkg/Sec/SecMain.c
> @@ -269,17 +269,17 @@ FindFfsFileAndSection (
>    for (EndOfFile = CurrentAddress + Fv->HeaderLength; ; ) {
>  
>      CurrentAddress = (EndOfFile + 7) & ~(7ULL);
>      if (CurrentAddress > EndOfFirmwareVolume) {
>        return EFI_VOLUME_CORRUPTED;
>      }
>  
>      File = (EFI_FFS_FILE_HEADER*)(UINTN) CurrentAddress;
> -    Size = *(UINT32*) File->Size & 0xffffff;
> +    Size = FFS_FILE_SIZE (File);
>      if (Size < (sizeof (*File) + sizeof (EFI_COMMON_SECTION_HEADER))) {
>        return EFI_VOLUME_CORRUPTED;
>      }
>  
>      EndOfFile = CurrentAddress + Size;
>      if (EndOfFile > EndOfFirmwareVolume) {
>        return EFI_VOLUME_CORRUPTED;
>      }
> @@ -600,17 +600,17 @@ FindImageBase (
>    for (EndOfFile = CurrentAddress + BootFirmwareVolumePtr->HeaderLength; ; ) {
>  
>      CurrentAddress = (EndOfFile + 7) & 0xfffffffffffffff8ULL;
>      if (CurrentAddress > EndOfFirmwareVolume) {
>        return EFI_NOT_FOUND;
>      }
>  
>      File = (EFI_FFS_FILE_HEADER*)(UINTN) CurrentAddress;
> -    Size = *(UINT32*) File->Size & 0xffffff;
> +    Size = FFS_FILE_SIZE (File);
>      if (Size < sizeof (*File)) {
>        return EFI_NOT_FOUND;
>      }
>  
>      EndOfFile = CurrentAddress + Size;
>      if (EndOfFile > EndOfFirmwareVolume) {
>        return EFI_NOT_FOUND;
>      }
> @@ -625,17 +625,17 @@ FindImageBase (
>      //
>      // Loop through the FFS file sections within the FFS file
>      //
>      EndOfSection = (EFI_PHYSICAL_ADDRESS)(UINTN) (File + 1);
>      for (;;) {
>        CurrentAddress = (EndOfSection + 3) & 0xfffffffffffffffcULL;
>        Section = (EFI_COMMON_SECTION_HEADER*)(UINTN) CurrentAddress;
>  
> -      Size = *(UINT32*) Section->Size & 0xffffff;
> +      Size = SECTION_SIZE (Section);
>        if (Size < sizeof (*Section)) {
>          return EFI_NOT_FOUND;
>        }
>  
>        EndOfSection = CurrentAddress + Size;
>        if (EndOfSection > EndOfFile) {
>          return EFI_NOT_FOUND;
>        }
> 

Reviewed-by: Philippe Mathieu-Daude <philmd@redhat.com>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [edk2-devel] [PATCH 07/10] OvmfPkg/AcpiPlatformDxe: suppress invalid "deref of undef pointer" warning
  2019-04-12 23:31 ` [PATCH 07/10] OvmfPkg/AcpiPlatformDxe: suppress invalid "deref of undef pointer" warning Laszlo Ersek
@ 2019-04-15 17:26   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 52+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-04-15 17:26 UTC (permalink / raw)
  To: devel, lersek; +Cc: Ard Biesheuvel, Jordan Justen

On 4/13/19 1:31 AM, Laszlo Ersek wrote:
> RH covscan emits the following false positive:
> 
>> Error: CLANG_WARNING:
>> edk2-89910a39dcfd/OvmfPkg/AcpiPlatformDxe/AcpiPlatform.c:182:14:
>> warning: Dereference of undefined pointer value
>> #    Status = FwVol->ReadSection (
>> #             ^~~~~~~~~~~~~~~~~~
>> edk2-89910a39dcfd/OvmfPkg/AcpiPlatformDxe/AcpiPlatform.c:164:7: note:
>> Assuming the condition is false
>> #  if (QemuDetected ()) {
>> #      ^~~~~~~~~~~~~~~
>> edk2-89910a39dcfd/OvmfPkg/AcpiPlatformDxe/AcpiPlatform.c:164:3: note:
>> Taking false branch
>> #  if (QemuDetected ()) {
>> #  ^
>> edk2-89910a39dcfd/OvmfPkg/AcpiPlatformDxe/AcpiPlatform.c:174:3: note:
>> Taking false branch
>> #  if (EFI_ERROR (Status)) {
>> #  ^
>> edk2-89910a39dcfd/OvmfPkg/AcpiPlatformDxe/AcpiPlatform.c:180:10: note:
>> Assuming 'Status' is equal to EFI_SUCCESS
>> #  while (Status == EFI_SUCCESS) {
>> #         ^~~~~~~~~~~~~~~~~~~~~
>> edk2-89910a39dcfd/OvmfPkg/AcpiPlatformDxe/AcpiPlatform.c:180:3: note:
>> Loop condition is true.  Entering loop body
>> #  while (Status == EFI_SUCCESS) {
>> #  ^
>> edk2-89910a39dcfd/OvmfPkg/AcpiPlatformDxe/AcpiPlatform.c:182:14: note:
>> Dereference of undefined pointer value
>> #    Status = FwVol->ReadSection (
>> #             ^~~~~~~~~~~~~~~~~~
>> #  180|     while (Status == EFI_SUCCESS) {
>> #  181|
>> #  182|->     Status = FwVol->ReadSection (
>> #  183|                         FwVol,
>> #  184|                         (EFI_GUID*)PcdGetPtr (PcdAcpiTableStorageFile),
> 
> This is invalid because LocateFvInstanceWithTables() sets FwVol on
> success.
> 
> Suppress the message by:
> - assigning FwVol NULL first (this would replace the original report with
>   "nullptr deref"),
> - asserting that FwVol is no longer NULL, on success.
> 
> What's important here is that ASSERT() ends with ANALYZER_UNREACHABLE() on
> failure.
> 
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Bugzilla: https://bugzilla.tianocore.org/show_bug.cgi?id=1710
> Issue: scan-0991.txt
> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> ---
>  OvmfPkg/AcpiPlatformDxe/AcpiPlatform.c | 7 +++++++
>  1 file changed, 7 insertions(+)
> 
> diff --git a/OvmfPkg/AcpiPlatformDxe/AcpiPlatform.c b/OvmfPkg/AcpiPlatformDxe/AcpiPlatform.c
> index f2c49953950b..2b529d58a15c 100644
> --- a/OvmfPkg/AcpiPlatformDxe/AcpiPlatform.c
> +++ b/OvmfPkg/AcpiPlatformDxe/AcpiPlatform.c
> @@ -156,23 +156,30 @@ InstallOvmfFvTables (
>    TableHandle  = 0;
>  
>    if (QemuDetected ()) {
>      TableInstallFunction = QemuInstallAcpiTable;
>    } else {
>      TableInstallFunction = InstallAcpiTable;
>    }
>  
> +  //
> +  // set FwVol (and use an ASSERT() below) to suppress incorrect
> +  // compiler/analyzer warnings
> +  //
> +  FwVol = NULL;
>    //
>    // Locate the firmware volume protocol
>    //
>    Status = LocateFvInstanceWithTables (&FwVol);
>    if (EFI_ERROR (Status)) {
>      return EFI_ABORTED;
>    }
> +  ASSERT (FwVol != NULL);
> +
>    //
>    // Read tables from the storage file.
>    //
>    while (Status == EFI_SUCCESS) {
>  
>      Status = FwVol->ReadSection (
>                        FwVol,
>                        (EFI_GUID*)PcdGetPtr (PcdAcpiTableStorageFile),
> 

Reviewed-by: Philippe Mathieu-Daude <philmd@redhat.com>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [edk2-devel] [PATCH 09/10] OvmfPkg/AcpiPlatformDxe: catch theoretical nullptr deref in Xen code
  2019-04-12 23:31 ` [PATCH 09/10] OvmfPkg/AcpiPlatformDxe: catch theoretical nullptr deref in Xen code Laszlo Ersek
@ 2019-04-15 17:28   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 52+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-04-15 17:28 UTC (permalink / raw)
  To: devel, lersek; +Cc: Anthony Perard, Ard Biesheuvel, Jordan Justen, Julien Grall

On 4/13/19 1:31 AM, Laszlo Ersek wrote:
> RH covscan justifiedly reports a path through InstallXenTables() where
> DsdtTable can technically remain NULL.
> 
> If this occurs in practice, then the guest and the VMM are out of sync on
> the interface contract. Catch the situation with a code snippet that halts
> in RELEASE builds, and in DEBUG builds lets the platform DSC control the
> assert disposition first (i.e. CPU exception, deadloop, or nothing).
> 
>> Error: CLANG_WARNING:
>> edk2-89910a39dcfd/OvmfPkg/AcpiPlatformDxe/Xen.c:309:14: warning: Access
>> to field 'Length' results in a dereference of a null pointer (loaded
>> from variable 'DsdtTable')
>> #             DsdtTable->Length,
>> #             ^~~~~~~~~
>> edk2-89910a39dcfd/OvmfPkg/AcpiPlatformDxe/Xen.c:154:3: note: Null
>> pointer value stored to 'DsdtTable'
>> #  DsdtTable   = NULL;
>> #  ^~~~~~~~~~~~~~~~~~
>> edk2-89910a39dcfd/OvmfPkg/AcpiPlatformDxe/Xen.c:162:3: note: Taking
>> false branch
>> #  if (EFI_ERROR (Status)) {
>> #  ^
>> edk2-89910a39dcfd/OvmfPkg/AcpiPlatformDxe/Xen.c:170:7: note: Assuming
>> the condition is false
>> #  if (XenAcpiRsdpStructurePtr->XsdtAddress) {
>> #      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> edk2-89910a39dcfd/OvmfPkg/AcpiPlatformDxe/Xen.c:170:3: note: Taking
>> false branch
>> #  if (XenAcpiRsdpStructurePtr->XsdtAddress) {
>> #  ^
>> edk2-89910a39dcfd/OvmfPkg/AcpiPlatformDxe/Xen.c:220:12: note: Assuming
>> the condition is false
>> #  else if (XenAcpiRsdpStructurePtr->RsdtAddress) {
>> #           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> edk2-89910a39dcfd/OvmfPkg/AcpiPlatformDxe/Xen.c:220:8: note: Taking
>> false branch
>> #  else if (XenAcpiRsdpStructurePtr->RsdtAddress) {
>> #       ^
>> edk2-89910a39dcfd/OvmfPkg/AcpiPlatformDxe/Xen.c:274:3: note: Taking
>> false branch
>> #  if (Fadt2Table) {
>> #  ^
>> edk2-89910a39dcfd/OvmfPkg/AcpiPlatformDxe/Xen.c:288:8: note: Taking
>> false branch
>> #  else if (Fadt1Table) {
>> #       ^
>> edk2-89910a39dcfd/OvmfPkg/AcpiPlatformDxe/Xen.c:309:14: note: Access to
>> field 'Length' results in a dereference of a null pointer (loaded from
>> variable 'DsdtTable')
>> #             DsdtTable->Length,
>> #             ^~~~~~~~~
>> #  307|                AcpiProtocol,
>> #  308|                DsdtTable,
>> #  309|->              DsdtTable->Length,
>> #  310|                &TableHandle
>> #  311|                );
> 
> Cc: Anthony Perard <anthony.perard@citrix.com>
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Julien Grall <julien.grall@arm.com>
> Bugzilla: https://bugzilla.tianocore.org/show_bug.cgi?id=1710
> Issue: scan-0993.txt
> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> ---
>  OvmfPkg/AcpiPlatformDxe/Xen.c | 9 ++++++++-
>  1 file changed, 8 insertions(+), 1 deletion(-)
> 
> diff --git a/OvmfPkg/AcpiPlatformDxe/Xen.c b/OvmfPkg/AcpiPlatformDxe/Xen.c
> index c8f275a8ee84..b21d3db74dc8 100644
> --- a/OvmfPkg/AcpiPlatformDxe/Xen.c
> +++ b/OvmfPkg/AcpiPlatformDxe/Xen.c
> @@ -295,18 +295,25 @@ InstallXenTables (
>                 &TableHandle
>                 );
>      if (EFI_ERROR (Status)) {
>        return Status;
>      }
>    }
>  
>    //
> -  // Install DSDT table.
> +  // Install DSDT table. If we reached this point without finding the DSDT,
> +  // then we're out of sync with the hypervisor, and cannot continue.
>    //
> +  if (DsdtTable == NULL) {
> +    DEBUG ((DEBUG_ERROR, "%a: no DSDT found\n", __FUNCTION__));
> +    ASSERT (FALSE);
> +    CpuDeadLoop ();
> +  }
> +
>    Status = InstallAcpiTable (
>               AcpiProtocol,
>               DsdtTable,
>               DsdtTable->Length,
>               &TableHandle
>               );
>    if (EFI_ERROR (Status)) {
>      return Status;
> 

Reviewed-by: Philippe Mathieu-Daude <philmd@redhat.com>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [edk2-devel] [PATCH 10/10] OvmfPkg/BasePciCapLib: suppress invalid "nullptr deref" warning
  2019-04-12 23:31 ` [PATCH 10/10] OvmfPkg/BasePciCapLib: suppress invalid "nullptr deref" warning Laszlo Ersek
@ 2019-04-15 17:31   ` Philippe Mathieu-Daudé
  2019-04-16 11:01     ` Laszlo Ersek
  0 siblings, 1 reply; 52+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-04-15 17:31 UTC (permalink / raw)
  To: devel, lersek; +Cc: Ard Biesheuvel, Jordan Justen

On 4/13/19 1:31 AM, Laszlo Ersek wrote:
> RH covscan reports the following "nullptr deref" warning:
> 
>> Error: CLANG_WARNING:
>> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:312:5:
>> warning: Dereference of null pointer
>> #    InstanceZero->NumInstancesUnion.NumInstances++;
>> #    ^
>> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:509:7:
>> note: Assuming 'OutCapList' is not equal to NULL
>> #  if (OutCapList == NULL) {
>> #      ^~~~~~~~~~~~~~~~~~
>> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:509:3:
>> note: Taking false branch
>> #  if (OutCapList == NULL) {
>> #  ^
>> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:518:7:
>> note: Assuming the condition is false
>> #  if (OutCapList->Capabilities == NULL) {
>> #      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:518:3:
>> note: Taking false branch
>> #  if (OutCapList->Capabilities == NULL) {
>> #  ^
>> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:529:7:
>> note: Assuming 'CapHdrOffsets' is not equal to NULL
>> #  if (CapHdrOffsets == NULL) {
>> #      ^~~~~~~~~~~~~~~~~~~~~
>> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:529:3:
>> note: Taking false branch
>> #  if (CapHdrOffsets == NULL) {
>> #  ^
>> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:546:3:
>> note: Taking false branch
>> #  if (RETURN_ERROR (Status)) {
>> #  ^
>> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:549:7:
>> note: Assuming the condition is true
>> #  if ((PciStatusReg & EFI_PCI_STATUS_CAPABILITY) != 0) {
>> #      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:549:3:
>> note: Taking true branch
>> #  if ((PciStatusReg & EFI_PCI_STATUS_CAPABILITY) != 0) {
>> #  ^
>> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:557:5:
>> note: Taking false branch
>> #    if (RETURN_ERROR (Status)) {
>> #    ^
>> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:565:12:
>> note: Assuming 'NormalCapHdrOffset' is > 0
>> #    while (NormalCapHdrOffset > 0) {
>> #           ^~~~~~~~~~~~~~~~~~~~~~
>> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:565:5:
>> note: Loop condition is true.  Entering loop body
>> #    while (NormalCapHdrOffset > 0) {
>> #    ^
>> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:570:7:
>> note: Taking false branch
>> #      if (RETURN_ERROR (Status)) {
>> #      ^
>> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:574:16:
>> note: Calling 'InsertPciCap'
>> #      Status = InsertPciCap (OutCapList, CapHdrOffsets, PciCapNormal,
>> #               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:235:3:
>> note: Null pointer value stored to 'InstanceZero'
>> #  InstanceZero = NULL;
>> #  ^~~~~~~~~~~~~~~~~~~
>> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:243:7:
>> note: Assuming 'PciCap' is not equal to NULL
>> #  if (PciCap == NULL) {
>> #      ^~~~~~~~~~~~~~
>> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:243:3:
>> note: Taking false branch
>> #  if (PciCap == NULL) {
>> #  ^
>> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:259:3:
>> note: Taking false branch
>> #  if (RETURN_ERROR (Status)) {
>> #  ^
>> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:297:3:
>> note: Taking false branch
>> #  if (RETURN_ERROR (Status)) {
>> #  ^
>> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:311:7:
>> note: Assuming the condition is true
>> #  if (PciCap->Key.Instance > 0) {
>> #      ^~~~~~~~~~~~~~~~~~~~~~~~
>> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:311:3:
>> note: Taking true branch
>> #  if (PciCap->Key.Instance > 0) {
>> #  ^
>> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:312:5:
>> note: Dereference of null pointer
>> #    InstanceZero->NumInstancesUnion.NumInstances++;
>> #    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> #  310|     //
>> #  311|     if (PciCap->Key.Instance > 0) {
>> #  312|->     InstanceZero->NumInstancesUnion.NumInstances++;
>> #  313|     }
>> #  314|     return RETURN_SUCCESS;
> 
> The warning is invalid: the flagged dereferencing of "InstanceZero" is
> gated by a condition that is only satisfied if we dereference
> "InstanceZero" *first*.
> 
> (Perhaps the analyzer assumes that the OrderedCollectionInsert() call,
> just before line 259, can change the value of "PciCap->Key.Instance" via
> the last argument:
> 
>    254    //
>    255    // Add PciCap to CapList.
>    256    //
>    257    Status = OrderedCollectionInsert (CapList->Capabilities, &PciCapEntry,
>    258               PciCap);
>    259    if (RETURN_ERROR (Status)) {
> 
> That assumption is incorrect.)
> 
> Add a comment and an ASSERT().
> 
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Bugzilla: https://bugzilla.tianocore.org/show_bug.cgi?id=1710
> Issue: scan-0994.txt
> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> ---
>  OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c | 7 +++++++
>  1 file changed, 7 insertions(+)
> 
> diff --git a/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c b/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c
> index 4968d2b478db..c6f2c726509f 100644
> --- a/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c
> +++ b/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c
> @@ -298,16 +298,23 @@ InsertPciCap (
>      goto DeletePciCapFromCapList;
>    }
>  
>    //
>    // Now we can bump the instance count maintained in Instance#0, if PciCap is
>    // not the first instance of (Domain, CapId).
>    //
>    if (PciCap->Key.Instance > 0) {
> +    //
> +    // Suppress invalid "nullptr dereference" compiler/analyzer warnings: the
> +    // only way for "PciCap->Key.Instance" to be positive here is for it to
> +    // have been assigned *from* dereferencing "InstanceZero" above.
> +    //
> +    ASSERT (InstanceZero != NULL);

What about adding a STATIC_ANALYZER_HINT() only defined by covscan?

       STATIC_ANALYZER_HINT (InstanceZero != NULL);

Regardless:
Reviewed-by: Philippe Mathieu-Daude <philmd@redhat.com>

> +
>      InstanceZero->NumInstancesUnion.NumInstances++;
>    }
>    return RETURN_SUCCESS;
>  
>  DeletePciCapFromCapList:
>    OrderedCollectionDelete (CapList->Capabilities, PciCapEntry, NULL);
>  
>  FreePciCap:
> 

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [edk2-devel] [PATCH 02/10] MdePkg/PiFirmwareFile: fix undefined behavior in SECTION_SIZE
  2019-04-15 16:15     ` Laszlo Ersek
@ 2019-04-16  8:28       ` Liming Gao
  2019-04-16  9:04       ` Jordan Justen
  1 sibling, 0 replies; 52+ messages in thread
From: Liming Gao @ 2019-04-16  8:28 UTC (permalink / raw)
  To: devel@edk2.groups.io, lersek@redhat.com, Justen, Jordan L,
	Kinney, Michael D

Laszlo:
  I think it is OK to add UNION type. UNION is not new data structure. It is convenience for developer to consume the data structure. This change is good to me. Reviewed-by: Liming Gao <liming.gao@intel.com>

Thanks
Liming
>-----Original Message-----
>From: devel@edk2.groups.io [mailto:devel@edk2.groups.io] On Behalf Of
>Laszlo Ersek
>Sent: Tuesday, April 16, 2019 12:16 AM
>To: Justen, Jordan L <jordan.l.justen@intel.com>; edk2-devel-groups-io
><devel@edk2.groups.io>; Kinney, Michael D <michael.d.kinney@intel.com>
>Cc: Gao, Liming <liming.gao@intel.com>
>Subject: Re: [edk2-devel] [PATCH 02/10] MdePkg/PiFirmwareFile: fix
>undefined behavior in SECTION_SIZE
>
>On 04/14/19 09:19, Jordan Justen wrote:
>> On 2019-04-12 16:31:20, Laszlo Ersek wrote:
>>> RH covscan justifiedly reports that accessing
>>> "EFI_COMMON_SECTION_HEADER.Size", which is of type UINT8[3],
>through a
>>> (UINT32*), is undefined behavior:
>>>
>>>> Error: OVERRUN (CWE-119):
>>>> edk2-89910a39dcfd/OvmfPkg/Sec/SecMain.c:178: overrun-local:
>Overrunning
>>>> array of 3 bytes at byte offset 3 by dereferencing pointer
>>>> "(UINT32 *)((EFI_COMMON_SECTION_HEADER *)(UINTN)Section)-
>>Size".
>>>> #  176|       Section = (EFI_COMMON_SECTION_HEADER*)(UINTN)
>CurrentAddress;
>>>> #  177|
>>>> #  178|->     Size = SECTION_SIZE (Section);
>>>> #  179|       if (Size < sizeof (*Section)) {
>>>> #  180|         return EFI_VOLUME_CORRUPTED;
>>>
>>> Fix this by introducing EFI_COMMON_SECTION_HEADER_UNION, and
>expressing
>>> SECTION_SIZE() in terms of
>"EFI_COMMON_SECTION_HEADER_UNION.Uint32".
>>>
>>> Cc: Liming Gao <liming.gao@intel.com>
>>> Cc: Michael D Kinney <michael.d.kinney@intel.com>
>>> Bugzilla: https://bugzilla.tianocore.org/show_bug.cgi?id=1710
>>> Issue: scan-1007.txt
>>> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
>>> ---
>>>  MdePkg/Include/Pi/PiFirmwareFile.h | 10 +++++++++-
>>>  1 file changed, 9 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/MdePkg/Include/Pi/PiFirmwareFile.h
>b/MdePkg/Include/Pi/PiFirmwareFile.h
>>> index a9f3bcc4eb8e..4fce8298d1c0 100644
>>> --- a/MdePkg/Include/Pi/PiFirmwareFile.h
>>> +++ b/MdePkg/Include/Pi/PiFirmwareFile.h
>>> @@ -229,16 +229,24 @@ typedef struct {
>>>    ///
>>>    UINT8             Size[3];
>>>    EFI_SECTION_TYPE  Type;
>>>    ///
>>>    /// Declares the section type.
>>>    ///
>>>  } EFI_COMMON_SECTION_HEADER;
>>>
>>> +///
>>> +/// Union that permits accessing EFI_COMMON_SECTION_HEADER as a
>UINT32 object.
>>> +///
>>> +typedef union {
>>> +  EFI_COMMON_SECTION_HEADER Hdr;
>>> +  UINT32                    Uint32;
>>> +} EFI_COMMON_SECTION_HEADER_UNION;
>>> +
>>>  typedef struct {
>>>    ///
>>>    /// A 24-bit unsigned integer that contains the total size of the section in
>bytes,
>>>    /// including the EFI_COMMON_SECTION_HEADER.
>>>    ///
>>>    UINT8             Size[3];
>>>
>>>    EFI_SECTION_TYPE  Type;
>>> @@ -476,17 +484,17 @@ typedef struct {
>>>    /// A UINT16 that represents a particular build. Subsequent builds have
>monotonically
>>>    /// increasing build numbers relative to earlier builds.
>>>    ///
>>>    UINT16                        BuildNumber;
>>>    CHAR16                        VersionString[1];
>>>  } EFI_VERSION_SECTION2;
>>>
>>>  #define SECTION_SIZE(SectionHeaderPtr) \
>>> -    ((UINT32) (*((UINT32 *) ((EFI_COMMON_SECTION_HEADER *) (UINTN)
>SectionHeaderPtr)->Size) & 0x00ffffff))
>>> +    (((EFI_COMMON_SECTION_HEADER_UNION *) (UINTN)
>(SectionHeaderPtr))->Uint32 & 0x00ffffff)
>>
>> Mike, all,
>>
>> Can we add a typedef for EFI_COMMON_SECTION_HEADER_UNION if it's
>not
>> in the PI spec?
>>
>> If it's not allowed, I think something like this might work too:
>>
>> #define SECTION_SIZE(SectionHeaderPtr) \
>>     (*((UINT32*)(UINTN)(SectionHeaderPtr)) & 0x00ffffff)
>
>(Less importantly:)
>
>It might shut up the static analyzer, but regarding the C standard, it's
>equally undefined behavior.
>
>Anyway I don't feel too strongly about this, given that we disable the
>strict aliasing / effective type rules in "tools_def.template"
>("-fno-strict-aliasing").
>
>> Then again, I see SECTION_SIZE is not in the spec, so maybe it's ok to
>> add the typedef.
>
>(More importantly:)
>
>Indeed the doubt you voice about ..._UNION crossed my mind, but then I
>too searched the PI spec for SECTION_SIZE, with no hits.
>
>Beyond that, I searched both the PI and UEFI specs, for "_UNION" --
>again no hits, despite our definitions of:
>
>- EFI_IMAGE_OPTIONAL_HEADER_UNION
>- EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION
>
>in
>
>- "MdePkg/Include/IndustryStandard/PeImage.h"
>- "MdePkg/Include/Protocol/GraphicsOutput.h"
>
>respectively.
>
>Thanks,
>Laszlo
>
>>
>> -Jordan
>>
>
>
>


^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [edk2-devel] [PATCH 02/10] MdePkg/PiFirmwareFile: fix undefined behavior in SECTION_SIZE
  2019-04-15 16:15     ` Laszlo Ersek
  2019-04-16  8:28       ` Liming Gao
@ 2019-04-16  9:04       ` Jordan Justen
  2019-04-16 10:59         ` Laszlo Ersek
  1 sibling, 1 reply; 52+ messages in thread
From: Jordan Justen @ 2019-04-16  9:04 UTC (permalink / raw)
  To: Laszlo Ersek, Michael D Kinney, edk2-devel-groups-io; +Cc: Liming Gao

On 2019-04-15 09:15:31, Laszlo Ersek wrote:
> On 04/14/19 09:19, Jordan Justen wrote:
> > On 2019-04-12 16:31:20, Laszlo Ersek wrote:
> >> RH covscan justifiedly reports that accessing
> >> "EFI_COMMON_SECTION_HEADER.Size", which is of type UINT8[3], through a
> >> (UINT32*), is undefined behavior:
> >>
> >>> Error: OVERRUN (CWE-119):
> >>> edk2-89910a39dcfd/OvmfPkg/Sec/SecMain.c:178: overrun-local: Overrunning
> >>> array of 3 bytes at byte offset 3 by dereferencing pointer
> >>> "(UINT32 *)((EFI_COMMON_SECTION_HEADER *)(UINTN)Section)->Size".
> >>> #  176|       Section = (EFI_COMMON_SECTION_HEADER*)(UINTN) CurrentAddress;
> >>> #  177|
> >>> #  178|->     Size = SECTION_SIZE (Section);
> >>> #  179|       if (Size < sizeof (*Section)) {
> >>> #  180|         return EFI_VOLUME_CORRUPTED;
> >>
> >> Fix this by introducing EFI_COMMON_SECTION_HEADER_UNION, and expressing
> >> SECTION_SIZE() in terms of "EFI_COMMON_SECTION_HEADER_UNION.Uint32".
> >>
> >> Cc: Liming Gao <liming.gao@intel.com>
> >> Cc: Michael D Kinney <michael.d.kinney@intel.com>
> >> Bugzilla: https://bugzilla.tianocore.org/show_bug.cgi?id=1710
> >> Issue: scan-1007.txt
> >> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> >> ---
> >>  MdePkg/Include/Pi/PiFirmwareFile.h | 10 +++++++++-
> >>  1 file changed, 9 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/MdePkg/Include/Pi/PiFirmwareFile.h b/MdePkg/Include/Pi/PiFirmwareFile.h
> >> index a9f3bcc4eb8e..4fce8298d1c0 100644
> >> --- a/MdePkg/Include/Pi/PiFirmwareFile.h
> >> +++ b/MdePkg/Include/Pi/PiFirmwareFile.h
> >> @@ -229,16 +229,24 @@ typedef struct {
> >>    ///
> >>    UINT8             Size[3];
> >>    EFI_SECTION_TYPE  Type;
> >>    ///
> >>    /// Declares the section type.
> >>    ///
> >>  } EFI_COMMON_SECTION_HEADER;
> >>  
> >> +///
> >> +/// Union that permits accessing EFI_COMMON_SECTION_HEADER as a UINT32 object.
> >> +///
> >> +typedef union {
> >> +  EFI_COMMON_SECTION_HEADER Hdr;
> >> +  UINT32                    Uint32;
> >> +} EFI_COMMON_SECTION_HEADER_UNION;
> >> +
> >>  typedef struct {
> >>    ///
> >>    /// A 24-bit unsigned integer that contains the total size of the section in bytes,
> >>    /// including the EFI_COMMON_SECTION_HEADER.
> >>    ///
> >>    UINT8             Size[3];
> >>  
> >>    EFI_SECTION_TYPE  Type;
> >> @@ -476,17 +484,17 @@ typedef struct {
> >>    /// A UINT16 that represents a particular build. Subsequent builds have monotonically
> >>    /// increasing build numbers relative to earlier builds.
> >>    ///
> >>    UINT16                        BuildNumber;
> >>    CHAR16                        VersionString[1];
> >>  } EFI_VERSION_SECTION2;
> >>  
> >>  #define SECTION_SIZE(SectionHeaderPtr) \
> >> -    ((UINT32) (*((UINT32 *) ((EFI_COMMON_SECTION_HEADER *) (UINTN) SectionHeaderPtr)->Size) & 0x00ffffff))
> >> +    (((EFI_COMMON_SECTION_HEADER_UNION *) (UINTN) (SectionHeaderPtr))->Uint32 & 0x00ffffff)
> > 
> > Mike, all,
> > 
> > Can we add a typedef for EFI_COMMON_SECTION_HEADER_UNION if it's not
> > in the PI spec?
> > 
> > If it's not allowed, I think something like this might work too:
> > 
> > #define SECTION_SIZE(SectionHeaderPtr) \
> >     (*((UINT32*)(UINTN)(SectionHeaderPtr)) & 0x00ffffff)
> 
> (Less importantly:)
> 
> It might shut up the static analyzer, but regarding the C standard, it's
> equally undefined behavior.

I think you are still accessing it through a UINT32*, since you are
using a pointer to a union, and an field of type UINT32 within the
union.

I guess it might more well defined to shift the bytes, like is
sometimes done with the FFS file sizes.

-Jordan

> Anyway I don't feel too strongly about this, given that we disable the
> strict aliasing / effective type rules in "tools_def.template"
> ("-fno-strict-aliasing").
> 
> > Then again, I see SECTION_SIZE is not in the spec, so maybe it's ok to
> > add the typedef.
> 
> (More importantly:)
> 
> Indeed the doubt you voice about ..._UNION crossed my mind, but then I
> too searched the PI spec for SECTION_SIZE, with no hits.
> 
> Beyond that, I searched both the PI and UEFI specs, for "_UNION" --
> again no hits, despite our definitions of:
> 
> - EFI_IMAGE_OPTIONAL_HEADER_UNION
> - EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION
> 
> in
> 
> - "MdePkg/Include/IndustryStandard/PeImage.h"
> - "MdePkg/Include/Protocol/GraphicsOutput.h"
> 
> respectively.
> 
> Thanks,
> Laszlo
> 
> > 
> > -Jordan
> > 
> 

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [edk2-devel] [PATCH 08/10] OvmfPkg: suppress "Value stored to ... is never read" analyzer warnings
  2019-04-15 16:25     ` Laszlo Ersek
@ 2019-04-16  9:26       ` Jordan Justen
  2019-04-16 11:44         ` Laszlo Ersek
  0 siblings, 1 reply; 52+ messages in thread
From: Jordan Justen @ 2019-04-16  9:26 UTC (permalink / raw)
  To: Laszlo Ersek, edk2-devel-groups-io
  Cc: Anthony Perard, Ard Biesheuvel, Julien Grall

On 2019-04-15 09:25:33, Laszlo Ersek wrote:
> On 04/14/19 10:03, Jordan Justen wrote:
> > On 2019-04-12 16:31:26, Laszlo Ersek wrote:
> >> RH covscan warns about assignments that it can determine are never
> >> "consumed" later ("dead stores"). The idea behind the warning is
> >> presumably that the programmer forgot to implement a dependent check
> >> somewhere.
> >>
> >> For each such warning that has been emitted for OvmfPkg,
> >> the case is one of the following however:
> >>
> >> - We assign a variable a value for (re-)initialization's sake, in
> >>   preparation for further or future uses. This practice is safe (sometimes
> >>   even recommended!), hence we should suppress these warnings.
> >>
> >> - We capture a result or a computation in a variable, following a general
> >>   programming pattern, but then decide to ignore the value in that
> >>   particular case. This is again safe, and we should suppress these
> >>   warnings too.
> >>
> >> According to the Clang documentation at
> >>
> >>   https://clang-analyzer.llvm.org/faq.html#dead_store
> >>
> >> we should use
> >>
> >>   (void)x;
> >>
> >> See the logs below (produced originally for edk2-stable201903).
> >>
> >>> Error: CLANG_WARNING:
> >>> edk2-89910a39dcfd/OvmfPkg/AcpiPlatformDxe/Xen.c:156:3: warning: Value
> >>> stored to 'NumberOfTableEntries' is never read
> >>> #  NumberOfTableEntries = 0;
> >>> #  ^                      ~
> >>> edk2-89910a39dcfd/OvmfPkg/AcpiPlatformDxe/Xen.c:156:3: note: Value
> >>> stored to 'NumberOfTableEntries' is never read
> >>> #  NumberOfTableEntries = 0;
> >>> #  ^                      ~
> >>> #  154|     DsdtTable   = NULL;
> >>> #  155|     TableHandle = 0;
> >>> #  156|->   NumberOfTableEntries = 0;
> >>> #  157|
> >>> #  158|     //
> >>>
> >>> Error: CLANG_WARNING:
> >>> edk2-89910a39dcfd/OvmfPkg/Library/PlatformBootManagerLib/QemuKernel.c:43:3:
> >>> warning: Value stored to 'SetupSize' is never read
> >>> #  SetupSize = 0;
> >>> #  ^           ~
> >>> edk2-89910a39dcfd/OvmfPkg/Library/PlatformBootManagerLib/QemuKernel.c:43:3:
> >>> note: Value stored to 'SetupSize' is never read
> >>> #  SetupSize = 0;
> >>> #  ^           ~
> >>> #   41|
> >>> #   42|     SetupBuf = NULL;
> >>> #   43|->   SetupSize = 0;
> >>> #   44|     KernelBuf = NULL;
> >>> #   45|     KernelInitialSize = 0;
> >>>
> >>> Error: CLANG_WARNING:
> >>> edk2-89910a39dcfd/OvmfPkg/Library/SerializeVariablesLib/SerializeVariablesLib.c:609:9:
> >>> warning: Value stored to 'VariableDataBufferSize' is never read
> >>> #        VariableDataBufferSize = 0;
> >>> #        ^                        ~
> >>> edk2-89910a39dcfd/OvmfPkg/Library/SerializeVariablesLib/SerializeVariablesLib.c:609:9:
> >>> note: Value stored to 'VariableDataBufferSize' is never read
> >>> #        VariableDataBufferSize = 0;
> >>> #        ^                        ~
> >>> #  607|           FreePool (VariableData);
> >>> #  608|           VariableData = NULL;
> >>> #  609|->         VariableDataBufferSize = 0;
> >>> #  610|         }
> >>> #  611|         VariableData = AllocatePool (VariableDataSize);
> >>>
> >>> Error: CLANG_WARNING:
> >>> edk2-89910a39dcfd/OvmfPkg/Library/VirtioLib/VirtioLib.c:125:3: warning:
> >>> Value stored to 'RingPagesPtr' is never read
> >>> #  RingPagesPtr += sizeof *Ring->Used.AvailEvent;
> >>> #  ^               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> >>> edk2-89910a39dcfd/OvmfPkg/Library/VirtioLib/VirtioLib.c:125:3: note:
> >>> Value stored to 'RingPagesPtr' is never read
> >>> #  RingPagesPtr += sizeof *Ring->Used.AvailEvent;
> >>> #  ^               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> >>> #  123|
> >>> #  124|     Ring->Used.AvailEvent = (volatile VOID *) RingPagesPtr;
> >>> #  125|->   RingPagesPtr += sizeof *Ring->Used.AvailEvent;
> >>> #  126|
> >>> #  127|     Ring->QueueSize = QueueSize;
> >>>
> >>> Error: CLANG_WARNING:
> >>> edk2-89910a39dcfd/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c:1079:3:
> >>> warning: Value stored to 'FwhInstance' is never read
> >>> #  FwhInstance = (EFI_FW_VOL_INSTANCE *)
> >>> #  ^             ~~~~~~~~~~~~~~~~~~~~~~~
> >>> edk2-89910a39dcfd/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c:1079:3:
> >>> note: Value stored to 'FwhInstance' is never read
> >>> #  FwhInstance = (EFI_FW_VOL_INSTANCE *)
> >>> #  ^             ~~~~~~~~~~~~~~~~~~~~~~~
> >>> # 1077|     ASSERT_RETURN_ERROR (PcdStatus);
> >>> # 1078|
> >>> # 1079|->   FwhInstance = (EFI_FW_VOL_INSTANCE *)
> >>> # 1080|       (
> >>> # 1081|         (UINTN) ((UINT8 *) FwhInstance) + FwVolHeader->HeaderLength +
> >>>
> >>> Error: CLANG_WARNING:
> >>> edk2-89910a39dcfd/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockServiceDxe.c:173:3:
> >>> warning: Value stored to 'Status' is never read
> >>> #  Status = gDS->RemoveMemorySpace (
> >>> #  ^        ~~~~~~~~~~~~~~~~~~~~~~~~
> >>> edk2-89910a39dcfd/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockServiceDxe.c:173:3:
> >>> note: Value stored to 'Status' is never read
> >>> #  Status = gDS->RemoveMemorySpace (
> >>> #  ^        ~~~~~~~~~~~~~~~~~~~~~~~~
> >>> #  171|     // Mark flash region as runtime memory
> >>> #  172|     //
> >>> #  173|->   Status = gDS->RemoveMemorySpace (
> >>> #  174|                     BaseAddress,
> >>> #  175|                     Length
> >>>
> >>> Error: CLANG_WARNING:
> >>> edk2-89910a39dcfd/OvmfPkg/SataControllerDxe/SataController.c:231:3:
> >>> warning: Value stored to 'DeviceUDmaMode' is never read
> >>> #  DeviceUDmaMode = 0;
> >>> #  ^                ~
> >>> edk2-89910a39dcfd/OvmfPkg/SataControllerDxe/SataController.c:231:3:
> >>> note: Value stored to 'DeviceUDmaMode' is never read
> >>> #  DeviceUDmaMode = 0;
> >>> #  ^                ~
> >>> #  229|     UINT16    DeviceUDmaMode;
> >>> #  230|
> >>> #  231|->   DeviceUDmaMode = 0;
> >>> #  232|
> >>> #  233|     //
> >>>
> >>> Error: CLANG_WARNING:
> >>> edk2-89910a39dcfd/OvmfPkg/VirtioGpuDxe/Gop.c:65:5: warning: Value stored
> >>> to 'Status' is never read
> >>> #    Status = VirtioGpuSetScanout (
> >>> #    ^        ~~~~~~~~~~~~~~~~~~~~~
> >>> edk2-89910a39dcfd/OvmfPkg/VirtioGpuDxe/Gop.c:65:5: note: Value stored to
> >>> 'Status' is never read
> >>> #    Status = VirtioGpuSetScanout (
> >>> #    ^        ~~~~~~~~~~~~~~~~~~~~~
> >>> #   63|       // by setting ResourceId=0 for it.
> >>> #   64|       //
> >>> #   65|->     Status = VirtioGpuSetScanout (
> >>> #   66|                  VgpuGop->ParentBus, // VgpuDev
> >>> #   67|                  0, 0, 0, 0,         // X, Y, Width, Height
> >>>
> >>> Error: CLANG_WARNING:
> >>> edk2-89910a39dcfd/OvmfPkg/VirtioNetDxe/SnpReceive.c:165:3: warning:
> >>> Value stored to 'RxPtr' is never read
> >>> #  RxPtr += sizeof (UINT16);
> >>> #  ^        ~~~~~~~~~~~~~~~
> >>> edk2-89910a39dcfd/OvmfPkg/VirtioNetDxe/SnpReceive.c:165:3: note: Value
> >>> stored to 'RxPtr' is never read
> >>> #  RxPtr += sizeof (UINT16);
> >>> #  ^        ~~~~~~~~~~~~~~~
> >>> #  163|       *Protocol = (UINT16) ((RxPtr[0] << 8) | RxPtr[1]);
> >>> #  164|     }
> >>> #  165|->   RxPtr += sizeof (UINT16);
> >>> #  166|
> >>> #  167|     Status = EFI_SUCCESS;
> >>
> >> Cc: Anthony Perard <anthony.perard@citrix.com>
> >> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> >> Cc: Jordan Justen <jordan.l.justen@intel.com>
> >> Cc: Julien Grall <julien.grall@arm.com>
> >> Bugzilla: https://bugzilla.tianocore.org/show_bug.cgi?id=1710
> >> Issue: scan-0992.txt
> >> Issue: scan-0996.txt
> >> Issue: scan-0997.txt
> >> Issue: scan-0998.txt
> >> Issue: scan-1000.txt
> >> Issue: scan-1001.txt
> >> Issue: scan-1006.txt
> >> Issue: scan-1011.txt
> >> Issue: scan-1012.txt
> >> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> >> ---
> >>  OvmfPkg/AcpiPlatformDxe/Xen.c                                 | 5 +++++
> >>  OvmfPkg/Library/PlatformBootManagerLib/QemuKernel.c           | 5 +++++
> >>  OvmfPkg/Library/SerializeVariablesLib/SerializeVariablesLib.c | 4 ++++
> >>  OvmfPkg/Library/VirtioLib/VirtioLib.c                         | 5 +++++
> >>  OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c       | 5 +++++
> >>  OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockServiceDxe.c    | 5 +++++
> >>  OvmfPkg/SataControllerDxe/SataController.c                    | 5 +++++
> >>  OvmfPkg/VirtioGpuDxe/Gop.c                                    | 6 ++++++
> >>  OvmfPkg/VirtioNetDxe/SnpReceive.c                             | 5 +++++
> >>  9 files changed, 45 insertions(+)
> >>
> >> diff --git a/OvmfPkg/AcpiPlatformDxe/Xen.c b/OvmfPkg/AcpiPlatformDxe/Xen.c
> >> index 357c60d23f4e..c8f275a8ee84 100644
> >> --- a/OvmfPkg/AcpiPlatformDxe/Xen.c
> >> +++ b/OvmfPkg/AcpiPlatformDxe/Xen.c
> >> @@ -144,16 +144,21 @@ InstallXenTables (
> >>    Fadt2Table  = NULL;
> >>    Fadt1Table  = NULL;
> >>    Facs2Table  = NULL;
> >>    Facs1Table  = NULL;
> >>    DsdtTable   = NULL;
> >>    TableHandle = 0;
> >>    NumberOfTableEntries = 0;
> >>  
> >> +  //
> >> +  // Suppress "Value stored to ... is never read" analyzer warnings.
> >> +  //
> >> +  (VOID)NumberOfTableEntries;
> >> +
> > 
> > I've seen this solution to shut up the compiler for similar reasons,
> > and it kind of bugs me.
> > 
> > It looks like both paths of the if & else initialize
> > NumberOfTableEntries, so maybe we can just drop setting it to 0?
> 
> It might trigger *other* compilers to whine about "variable read without
> initialization" :)
> 
> > I looked at FwhInstance too, and it doesn't look like it is used after
> > being set. So, maybe that should just be dropped?
> > 
> > I guess both of your bullet points give arguments allowing the unused
> > set.
> > 
> > Rather than adding "Suppress..." comments everywhere, maybe a global
> > macro could be defined for similar uses in EDK II?
> > 
> > //
> > // Suppress "Value stored to ... is never read" analyzer warnings.
> > //
> > #define IGNORE_UNUSED_ASSIGNMENT(var) ((VOID)var)
> > 
> > Then again, I guess we decided to suppress this in EDK II compiler
> > warnings with -Wno-unused-but-set-variable.
> > 
> > So, can you adjust the RH covscan tool settings to similarly ignore
> > these warnings?
> 
> I think that should be possible, yes. AIUI it is supposed to have
> location-sensitive permanent overrides (maintained outside of the source
> code), and it should be doing incremental / differential scanning --
> report only "new" issues.

I think if the setting can be tweaked, maybe most of these changes
wouldn't be needed. But, it also might prevent you from having to
"fix" similar issues in the future.

> Admittedly, I hate most of the warning suppression patches myself,
> littering our code -- and that applies to all the *historical* spurious
> assignments that we already have in place --, so I'm 100% fine with
> dropping this patch (and other suppression patches too, if that is the
> upstream edk2 project's preference!)

In MdePkg/Include/X64/ProcessorBind.h, I see:

//
// Disable ICC's remark #593: "Variable" was set but never used.
// This is legal ANSI C code so we disable the remark that is turned on with /W4
//
#pragma warning ( disable : 593 )

And, then we have -Wno-unused-but-set-variable for GCC.

Regarding "spurious assignments", MdePkg/Include/X64/ProcessorBind.h,
I also see:

//
// This warning is for potentially uninitialized local variable, and it may cause false
// positive issues in VS2013 and VS2015 build
//
#pragma warning ( disable : 4701 )

-Jordan

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [edk2-devel] [PATCH 02/10] MdePkg/PiFirmwareFile: fix undefined behavior in SECTION_SIZE
  2019-04-16  9:04       ` Jordan Justen
@ 2019-04-16 10:59         ` Laszlo Ersek
  2019-04-16 16:50           ` Philippe Mathieu-Daudé
  2019-04-16 18:48           ` Jordan Justen
  0 siblings, 2 replies; 52+ messages in thread
From: Laszlo Ersek @ 2019-04-16 10:59 UTC (permalink / raw)
  To: Jordan Justen, Michael D Kinney, edk2-devel-groups-io; +Cc: Liming Gao

On 04/16/19 11:04, Jordan Justen wrote:
> On 2019-04-15 09:15:31, Laszlo Ersek wrote:
>> On 04/14/19 09:19, Jordan Justen wrote:
>>> On 2019-04-12 16:31:20, Laszlo Ersek wrote:
>>>> RH covscan justifiedly reports that accessing
>>>> "EFI_COMMON_SECTION_HEADER.Size", which is of type UINT8[3], through a
>>>> (UINT32*), is undefined behavior:
>>>>
>>>>> Error: OVERRUN (CWE-119):
>>>>> edk2-89910a39dcfd/OvmfPkg/Sec/SecMain.c:178: overrun-local: Overrunning
>>>>> array of 3 bytes at byte offset 3 by dereferencing pointer
>>>>> "(UINT32 *)((EFI_COMMON_SECTION_HEADER *)(UINTN)Section)->Size".
>>>>> #  176|       Section = (EFI_COMMON_SECTION_HEADER*)(UINTN) CurrentAddress;
>>>>> #  177|
>>>>> #  178|->     Size = SECTION_SIZE (Section);
>>>>> #  179|       if (Size < sizeof (*Section)) {
>>>>> #  180|         return EFI_VOLUME_CORRUPTED;
>>>>
>>>> Fix this by introducing EFI_COMMON_SECTION_HEADER_UNION, and expressing
>>>> SECTION_SIZE() in terms of "EFI_COMMON_SECTION_HEADER_UNION.Uint32".
>>>>
>>>> Cc: Liming Gao <liming.gao@intel.com>
>>>> Cc: Michael D Kinney <michael.d.kinney@intel.com>
>>>> Bugzilla: https://bugzilla.tianocore.org/show_bug.cgi?id=1710
>>>> Issue: scan-1007.txt
>>>> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
>>>> ---
>>>>  MdePkg/Include/Pi/PiFirmwareFile.h | 10 +++++++++-
>>>>  1 file changed, 9 insertions(+), 1 deletion(-)
>>>>
>>>> diff --git a/MdePkg/Include/Pi/PiFirmwareFile.h b/MdePkg/Include/Pi/PiFirmwareFile.h
>>>> index a9f3bcc4eb8e..4fce8298d1c0 100644
>>>> --- a/MdePkg/Include/Pi/PiFirmwareFile.h
>>>> +++ b/MdePkg/Include/Pi/PiFirmwareFile.h
>>>> @@ -229,16 +229,24 @@ typedef struct {
>>>>    ///
>>>>    UINT8             Size[3];
>>>>    EFI_SECTION_TYPE  Type;
>>>>    ///
>>>>    /// Declares the section type.
>>>>    ///
>>>>  } EFI_COMMON_SECTION_HEADER;
>>>>  
>>>> +///
>>>> +/// Union that permits accessing EFI_COMMON_SECTION_HEADER as a UINT32 object.
>>>> +///
>>>> +typedef union {
>>>> +  EFI_COMMON_SECTION_HEADER Hdr;
>>>> +  UINT32                    Uint32;
>>>> +} EFI_COMMON_SECTION_HEADER_UNION;
>>>> +
>>>>  typedef struct {
>>>>    ///
>>>>    /// A 24-bit unsigned integer that contains the total size of the section in bytes,
>>>>    /// including the EFI_COMMON_SECTION_HEADER.
>>>>    ///
>>>>    UINT8             Size[3];
>>>>  
>>>>    EFI_SECTION_TYPE  Type;
>>>> @@ -476,17 +484,17 @@ typedef struct {
>>>>    /// A UINT16 that represents a particular build. Subsequent builds have monotonically
>>>>    /// increasing build numbers relative to earlier builds.
>>>>    ///
>>>>    UINT16                        BuildNumber;
>>>>    CHAR16                        VersionString[1];
>>>>  } EFI_VERSION_SECTION2;
>>>>  
>>>>  #define SECTION_SIZE(SectionHeaderPtr) \
>>>> -    ((UINT32) (*((UINT32 *) ((EFI_COMMON_SECTION_HEADER *) (UINTN) SectionHeaderPtr)->Size) & 0x00ffffff))
>>>> +    (((EFI_COMMON_SECTION_HEADER_UNION *) (UINTN) (SectionHeaderPtr))->Uint32 & 0x00ffffff)
>>>
>>> Mike, all,
>>>
>>> Can we add a typedef for EFI_COMMON_SECTION_HEADER_UNION if it's not
>>> in the PI spec?
>>>
>>> If it's not allowed, I think something like this might work too:
>>>
>>> #define SECTION_SIZE(SectionHeaderPtr) \
>>>     (*((UINT32*)(UINTN)(SectionHeaderPtr)) & 0x00ffffff)
>>
>> (Less importantly:)
>>
>> It might shut up the static analyzer, but regarding the C standard, it's
>> equally undefined behavior.
> 
> I think you are still accessing it through a UINT32*, since you are
> using a pointer to a union, and an field of type UINT32 within the
> union.

Using a union makes the behavior well-defined.

> 6.2.7 Compatible type and composite type
>
> 1 Two types have compatible type if their types are the same.
>   Additional rules for determining whether two types are compatible
>   are described in [...]

> 6.5 Expressions
>
> 6 The /effective type/ of an object for an access to its stored value
>   is the declared type of the object, if any. [...]
>
> 7 An object shall have its stored value accessed only by an lvalue
>   expression that has one of the following types:
>
>   — a type compatible with the effective type of the object,
>   — a qualified version of a type compatible with the effective type
>     of the object,
>   — a type that is the signed or unsigned type corresponding to the
>     effective type of the object,
>   — a type that is the signed or unsigned type corresponding to a
>     qualified version of the effective type of the object,
>   — an aggregate or union type that includes one of the aforementioned
>     types among its members (including, recursively, a member of a
>     subaggregate or contained union), or
>   — a character type.

- Regarding 6.5p6, the original object we intend to access has
(declared) type EFI_COMMON_SECTION_HEADER. Therefore the effective type
is EFI_COMMON_SECTION_HEADER.

- Based on 6.2.7p1, EFI_COMMON_SECTION_HEADER is compatible with
EFI_COMMON_SECTION_HEADER. (Because they are the same.)

- Based on 6.5p7 item #5, EFI_COMMON_SECTION_HEADER can be accessed as
EFI_COMMON_SECTION_HEADER_UNION, because EFI_COMMON_SECTION_HEADER_UNION
includes "a type compatible with the effective type of the object" (#1)
among its members -- namely an EFI_COMMON_SECTION_HEADER, which is
compatible with EFI_COMMON_SECTION_HEADER, because they are the same.

> I guess it might more well defined to shift the bytes, like is
> sometimes done with the FFS file sizes.

I did that (i.e. byte-shifting) in the other patch:

  [edk2-devel] [PATCH 04/10]
  MdePkg/PiFirmwareFile: fix undefined behavior in FFS_FILE_SIZE

but for SECTION_SIZE, the union is well-defined too.

Thanks,
Laszlo

> 
> -Jordan
> 
>> Anyway I don't feel too strongly about this, given that we disable the
>> strict aliasing / effective type rules in "tools_def.template"
>> ("-fno-strict-aliasing").
>>
>>> Then again, I see SECTION_SIZE is not in the spec, so maybe it's ok to
>>> add the typedef.
>>
>> (More importantly:)
>>
>> Indeed the doubt you voice about ..._UNION crossed my mind, but then I
>> too searched the PI spec for SECTION_SIZE, with no hits.
>>
>> Beyond that, I searched both the PI and UEFI specs, for "_UNION" --
>> again no hits, despite our definitions of:
>>
>> - EFI_IMAGE_OPTIONAL_HEADER_UNION
>> - EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION
>>
>> in
>>
>> - "MdePkg/Include/IndustryStandard/PeImage.h"
>> - "MdePkg/Include/Protocol/GraphicsOutput.h"
>>
>> respectively.
>>
>> Thanks,
>> Laszlo
>>
>>>
>>> -Jordan
>>>
>>


^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [edk2-devel] [PATCH 10/10] OvmfPkg/BasePciCapLib: suppress invalid "nullptr deref" warning
  2019-04-15 17:31   ` [edk2-devel] " Philippe Mathieu-Daudé
@ 2019-04-16 11:01     ` Laszlo Ersek
  0 siblings, 0 replies; 52+ messages in thread
From: Laszlo Ersek @ 2019-04-16 11:01 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, devel; +Cc: Ard Biesheuvel, Jordan Justen

On 04/15/19 19:31, Philippe Mathieu-Daudé wrote:
> On 4/13/19 1:31 AM, Laszlo Ersek wrote:
>> RH covscan reports the following "nullptr deref" warning:
>>
>>> Error: CLANG_WARNING:
>>> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:312:5:
>>> warning: Dereference of null pointer
>>> #    InstanceZero->NumInstancesUnion.NumInstances++;
>>> #    ^
>>> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:509:7:
>>> note: Assuming 'OutCapList' is not equal to NULL
>>> #  if (OutCapList == NULL) {
>>> #      ^~~~~~~~~~~~~~~~~~
>>> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:509:3:
>>> note: Taking false branch
>>> #  if (OutCapList == NULL) {
>>> #  ^
>>> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:518:7:
>>> note: Assuming the condition is false
>>> #  if (OutCapList->Capabilities == NULL) {
>>> #      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:518:3:
>>> note: Taking false branch
>>> #  if (OutCapList->Capabilities == NULL) {
>>> #  ^
>>> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:529:7:
>>> note: Assuming 'CapHdrOffsets' is not equal to NULL
>>> #  if (CapHdrOffsets == NULL) {
>>> #      ^~~~~~~~~~~~~~~~~~~~~
>>> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:529:3:
>>> note: Taking false branch
>>> #  if (CapHdrOffsets == NULL) {
>>> #  ^
>>> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:546:3:
>>> note: Taking false branch
>>> #  if (RETURN_ERROR (Status)) {
>>> #  ^
>>> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:549:7:
>>> note: Assuming the condition is true
>>> #  if ((PciStatusReg & EFI_PCI_STATUS_CAPABILITY) != 0) {
>>> #      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:549:3:
>>> note: Taking true branch
>>> #  if ((PciStatusReg & EFI_PCI_STATUS_CAPABILITY) != 0) {
>>> #  ^
>>> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:557:5:
>>> note: Taking false branch
>>> #    if (RETURN_ERROR (Status)) {
>>> #    ^
>>> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:565:12:
>>> note: Assuming 'NormalCapHdrOffset' is > 0
>>> #    while (NormalCapHdrOffset > 0) {
>>> #           ^~~~~~~~~~~~~~~~~~~~~~
>>> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:565:5:
>>> note: Loop condition is true.  Entering loop body
>>> #    while (NormalCapHdrOffset > 0) {
>>> #    ^
>>> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:570:7:
>>> note: Taking false branch
>>> #      if (RETURN_ERROR (Status)) {
>>> #      ^
>>> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:574:16:
>>> note: Calling 'InsertPciCap'
>>> #      Status = InsertPciCap (OutCapList, CapHdrOffsets, PciCapNormal,
>>> #               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:235:3:
>>> note: Null pointer value stored to 'InstanceZero'
>>> #  InstanceZero = NULL;
>>> #  ^~~~~~~~~~~~~~~~~~~
>>> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:243:7:
>>> note: Assuming 'PciCap' is not equal to NULL
>>> #  if (PciCap == NULL) {
>>> #      ^~~~~~~~~~~~~~
>>> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:243:3:
>>> note: Taking false branch
>>> #  if (PciCap == NULL) {
>>> #  ^
>>> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:259:3:
>>> note: Taking false branch
>>> #  if (RETURN_ERROR (Status)) {
>>> #  ^
>>> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:297:3:
>>> note: Taking false branch
>>> #  if (RETURN_ERROR (Status)) {
>>> #  ^
>>> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:311:7:
>>> note: Assuming the condition is true
>>> #  if (PciCap->Key.Instance > 0) {
>>> #      ^~~~~~~~~~~~~~~~~~~~~~~~
>>> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:311:3:
>>> note: Taking true branch
>>> #  if (PciCap->Key.Instance > 0) {
>>> #  ^
>>> edk2-89910a39dcfd/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c:312:5:
>>> note: Dereference of null pointer
>>> #    InstanceZero->NumInstancesUnion.NumInstances++;
>>> #    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>> #  310|     //
>>> #  311|     if (PciCap->Key.Instance > 0) {
>>> #  312|->     InstanceZero->NumInstancesUnion.NumInstances++;
>>> #  313|     }
>>> #  314|     return RETURN_SUCCESS;
>>
>> The warning is invalid: the flagged dereferencing of "InstanceZero" is
>> gated by a condition that is only satisfied if we dereference
>> "InstanceZero" *first*.
>>
>> (Perhaps the analyzer assumes that the OrderedCollectionInsert() call,
>> just before line 259, can change the value of "PciCap->Key.Instance" via
>> the last argument:
>>
>>    254    //
>>    255    // Add PciCap to CapList.
>>    256    //
>>    257    Status = OrderedCollectionInsert (CapList->Capabilities, &PciCapEntry,
>>    258               PciCap);
>>    259    if (RETURN_ERROR (Status)) {
>>
>> That assumption is incorrect.)
>>
>> Add a comment and an ASSERT().
>>
>> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
>> Cc: Jordan Justen <jordan.l.justen@intel.com>
>> Bugzilla: https://bugzilla.tianocore.org/show_bug.cgi?id=1710
>> Issue: scan-0994.txt
>> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
>> ---
>>  OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c | 7 +++++++
>>  1 file changed, 7 insertions(+)
>>
>> diff --git a/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c b/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c
>> index 4968d2b478db..c6f2c726509f 100644
>> --- a/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c
>> +++ b/OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c
>> @@ -298,16 +298,23 @@ InsertPciCap (
>>      goto DeletePciCapFromCapList;
>>    }
>>  
>>    //
>>    // Now we can bump the instance count maintained in Instance#0, if PciCap is
>>    // not the first instance of (Domain, CapId).
>>    //
>>    if (PciCap->Key.Instance > 0) {
>> +    //
>> +    // Suppress invalid "nullptr dereference" compiler/analyzer warnings: the
>> +    // only way for "PciCap->Key.Instance" to be positive here is for it to
>> +    // have been assigned *from* dereferencing "InstanceZero" above.
>> +    //
>> +    ASSERT (InstanceZero != NULL);
> 
> What about adding a STATIC_ANALYZER_HINT() only defined by covscan?
> 
>        STATIC_ANALYZER_HINT (InstanceZero != NULL);

We'd have to #define STATIC_ANALYZER_HINT in "MdePkg/Include/Base.h",
somehow.

> 
> Regardless:
> Reviewed-by: Philippe Mathieu-Daude <philmd@redhat.com>

Thanks! (For the other reviews too.)
Laszlo

> 
>> +
>>      InstanceZero->NumInstancesUnion.NumInstances++;
>>    }
>>    return RETURN_SUCCESS;
>>  
>>  DeletePciCapFromCapList:
>>    OrderedCollectionDelete (CapList->Capabilities, PciCapEntry, NULL);
>>  
>>  FreePciCap:
>>


^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [edk2-devel] [PATCH 08/10] OvmfPkg: suppress "Value stored to ... is never read" analyzer warnings
  2019-04-16  9:26       ` Jordan Justen
@ 2019-04-16 11:44         ` Laszlo Ersek
  0 siblings, 0 replies; 52+ messages in thread
From: Laszlo Ersek @ 2019-04-16 11:44 UTC (permalink / raw)
  To: Jordan Justen, edk2-devel-groups-io
  Cc: Anthony Perard, Ard Biesheuvel, Julien Grall

On 04/16/19 11:26, Jordan Justen wrote:
> On 2019-04-15 09:25:33, Laszlo Ersek wrote:
>> On 04/14/19 10:03, Jordan Justen wrote:
>>> On 2019-04-12 16:31:26, Laszlo Ersek wrote:
>>>> RH covscan warns about assignments that it can determine are never
>>>> "consumed" later ("dead stores"). The idea behind the warning is
>>>> presumably that the programmer forgot to implement a dependent check
>>>> somewhere.
>>>>
>>>> For each such warning that has been emitted for OvmfPkg,
>>>> the case is one of the following however:
>>>>
>>>> - We assign a variable a value for (re-)initialization's sake, in
>>>>   preparation for further or future uses. This practice is safe (sometimes
>>>>   even recommended!), hence we should suppress these warnings.
>>>>
>>>> - We capture a result or a computation in a variable, following a general
>>>>   programming pattern, but then decide to ignore the value in that
>>>>   particular case. This is again safe, and we should suppress these
>>>>   warnings too.
>>>>
>>>> According to the Clang documentation at
>>>>
>>>>   https://clang-analyzer.llvm.org/faq.html#dead_store
>>>>
>>>> we should use
>>>>
>>>>   (void)x;
>>>>
>>>> See the logs below (produced originally for edk2-stable201903).
>>>>
>>>>> Error: CLANG_WARNING:
>>>>> edk2-89910a39dcfd/OvmfPkg/AcpiPlatformDxe/Xen.c:156:3: warning: Value
>>>>> stored to 'NumberOfTableEntries' is never read
>>>>> #  NumberOfTableEntries = 0;
>>>>> #  ^                      ~
>>>>> edk2-89910a39dcfd/OvmfPkg/AcpiPlatformDxe/Xen.c:156:3: note: Value
>>>>> stored to 'NumberOfTableEntries' is never read
>>>>> #  NumberOfTableEntries = 0;
>>>>> #  ^                      ~
>>>>> #  154|     DsdtTable   = NULL;
>>>>> #  155|     TableHandle = 0;
>>>>> #  156|->   NumberOfTableEntries = 0;
>>>>> #  157|
>>>>> #  158|     //
>>>>>
>>>>> Error: CLANG_WARNING:
>>>>> edk2-89910a39dcfd/OvmfPkg/Library/PlatformBootManagerLib/QemuKernel.c:43:3:
>>>>> warning: Value stored to 'SetupSize' is never read
>>>>> #  SetupSize = 0;
>>>>> #  ^           ~
>>>>> edk2-89910a39dcfd/OvmfPkg/Library/PlatformBootManagerLib/QemuKernel.c:43:3:
>>>>> note: Value stored to 'SetupSize' is never read
>>>>> #  SetupSize = 0;
>>>>> #  ^           ~
>>>>> #   41|
>>>>> #   42|     SetupBuf = NULL;
>>>>> #   43|->   SetupSize = 0;
>>>>> #   44|     KernelBuf = NULL;
>>>>> #   45|     KernelInitialSize = 0;
>>>>>
>>>>> Error: CLANG_WARNING:
>>>>> edk2-89910a39dcfd/OvmfPkg/Library/SerializeVariablesLib/SerializeVariablesLib.c:609:9:
>>>>> warning: Value stored to 'VariableDataBufferSize' is never read
>>>>> #        VariableDataBufferSize = 0;
>>>>> #        ^                        ~
>>>>> edk2-89910a39dcfd/OvmfPkg/Library/SerializeVariablesLib/SerializeVariablesLib.c:609:9:
>>>>> note: Value stored to 'VariableDataBufferSize' is never read
>>>>> #        VariableDataBufferSize = 0;
>>>>> #        ^                        ~
>>>>> #  607|           FreePool (VariableData);
>>>>> #  608|           VariableData = NULL;
>>>>> #  609|->         VariableDataBufferSize = 0;
>>>>> #  610|         }
>>>>> #  611|         VariableData = AllocatePool (VariableDataSize);
>>>>>
>>>>> Error: CLANG_WARNING:
>>>>> edk2-89910a39dcfd/OvmfPkg/Library/VirtioLib/VirtioLib.c:125:3: warning:
>>>>> Value stored to 'RingPagesPtr' is never read
>>>>> #  RingPagesPtr += sizeof *Ring->Used.AvailEvent;
>>>>> #  ^               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>>>> edk2-89910a39dcfd/OvmfPkg/Library/VirtioLib/VirtioLib.c:125:3: note:
>>>>> Value stored to 'RingPagesPtr' is never read
>>>>> #  RingPagesPtr += sizeof *Ring->Used.AvailEvent;
>>>>> #  ^               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>>>> #  123|
>>>>> #  124|     Ring->Used.AvailEvent = (volatile VOID *) RingPagesPtr;
>>>>> #  125|->   RingPagesPtr += sizeof *Ring->Used.AvailEvent;
>>>>> #  126|
>>>>> #  127|     Ring->QueueSize = QueueSize;
>>>>>
>>>>> Error: CLANG_WARNING:
>>>>> edk2-89910a39dcfd/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c:1079:3:
>>>>> warning: Value stored to 'FwhInstance' is never read
>>>>> #  FwhInstance = (EFI_FW_VOL_INSTANCE *)
>>>>> #  ^             ~~~~~~~~~~~~~~~~~~~~~~~
>>>>> edk2-89910a39dcfd/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c:1079:3:
>>>>> note: Value stored to 'FwhInstance' is never read
>>>>> #  FwhInstance = (EFI_FW_VOL_INSTANCE *)
>>>>> #  ^             ~~~~~~~~~~~~~~~~~~~~~~~
>>>>> # 1077|     ASSERT_RETURN_ERROR (PcdStatus);
>>>>> # 1078|
>>>>> # 1079|->   FwhInstance = (EFI_FW_VOL_INSTANCE *)
>>>>> # 1080|       (
>>>>> # 1081|         (UINTN) ((UINT8 *) FwhInstance) + FwVolHeader->HeaderLength +
>>>>>
>>>>> Error: CLANG_WARNING:
>>>>> edk2-89910a39dcfd/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockServiceDxe.c:173:3:
>>>>> warning: Value stored to 'Status' is never read
>>>>> #  Status = gDS->RemoveMemorySpace (
>>>>> #  ^        ~~~~~~~~~~~~~~~~~~~~~~~~
>>>>> edk2-89910a39dcfd/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockServiceDxe.c:173:3:
>>>>> note: Value stored to 'Status' is never read
>>>>> #  Status = gDS->RemoveMemorySpace (
>>>>> #  ^        ~~~~~~~~~~~~~~~~~~~~~~~~
>>>>> #  171|     // Mark flash region as runtime memory
>>>>> #  172|     //
>>>>> #  173|->   Status = gDS->RemoveMemorySpace (
>>>>> #  174|                     BaseAddress,
>>>>> #  175|                     Length
>>>>>
>>>>> Error: CLANG_WARNING:
>>>>> edk2-89910a39dcfd/OvmfPkg/SataControllerDxe/SataController.c:231:3:
>>>>> warning: Value stored to 'DeviceUDmaMode' is never read
>>>>> #  DeviceUDmaMode = 0;
>>>>> #  ^                ~
>>>>> edk2-89910a39dcfd/OvmfPkg/SataControllerDxe/SataController.c:231:3:
>>>>> note: Value stored to 'DeviceUDmaMode' is never read
>>>>> #  DeviceUDmaMode = 0;
>>>>> #  ^                ~
>>>>> #  229|     UINT16    DeviceUDmaMode;
>>>>> #  230|
>>>>> #  231|->   DeviceUDmaMode = 0;
>>>>> #  232|
>>>>> #  233|     //
>>>>>
>>>>> Error: CLANG_WARNING:
>>>>> edk2-89910a39dcfd/OvmfPkg/VirtioGpuDxe/Gop.c:65:5: warning: Value stored
>>>>> to 'Status' is never read
>>>>> #    Status = VirtioGpuSetScanout (
>>>>> #    ^        ~~~~~~~~~~~~~~~~~~~~~
>>>>> edk2-89910a39dcfd/OvmfPkg/VirtioGpuDxe/Gop.c:65:5: note: Value stored to
>>>>> 'Status' is never read
>>>>> #    Status = VirtioGpuSetScanout (
>>>>> #    ^        ~~~~~~~~~~~~~~~~~~~~~
>>>>> #   63|       // by setting ResourceId=0 for it.
>>>>> #   64|       //
>>>>> #   65|->     Status = VirtioGpuSetScanout (
>>>>> #   66|                  VgpuGop->ParentBus, // VgpuDev
>>>>> #   67|                  0, 0, 0, 0,         // X, Y, Width, Height
>>>>>
>>>>> Error: CLANG_WARNING:
>>>>> edk2-89910a39dcfd/OvmfPkg/VirtioNetDxe/SnpReceive.c:165:3: warning:
>>>>> Value stored to 'RxPtr' is never read
>>>>> #  RxPtr += sizeof (UINT16);
>>>>> #  ^        ~~~~~~~~~~~~~~~
>>>>> edk2-89910a39dcfd/OvmfPkg/VirtioNetDxe/SnpReceive.c:165:3: note: Value
>>>>> stored to 'RxPtr' is never read
>>>>> #  RxPtr += sizeof (UINT16);
>>>>> #  ^        ~~~~~~~~~~~~~~~
>>>>> #  163|       *Protocol = (UINT16) ((RxPtr[0] << 8) | RxPtr[1]);
>>>>> #  164|     }
>>>>> #  165|->   RxPtr += sizeof (UINT16);
>>>>> #  166|
>>>>> #  167|     Status = EFI_SUCCESS;
>>>>
>>>> Cc: Anthony Perard <anthony.perard@citrix.com>
>>>> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
>>>> Cc: Jordan Justen <jordan.l.justen@intel.com>
>>>> Cc: Julien Grall <julien.grall@arm.com>
>>>> Bugzilla: https://bugzilla.tianocore.org/show_bug.cgi?id=1710
>>>> Issue: scan-0992.txt
>>>> Issue: scan-0996.txt
>>>> Issue: scan-0997.txt
>>>> Issue: scan-0998.txt
>>>> Issue: scan-1000.txt
>>>> Issue: scan-1001.txt
>>>> Issue: scan-1006.txt
>>>> Issue: scan-1011.txt
>>>> Issue: scan-1012.txt
>>>> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
>>>> ---
>>>>  OvmfPkg/AcpiPlatformDxe/Xen.c                                 | 5 +++++
>>>>  OvmfPkg/Library/PlatformBootManagerLib/QemuKernel.c           | 5 +++++
>>>>  OvmfPkg/Library/SerializeVariablesLib/SerializeVariablesLib.c | 4 ++++
>>>>  OvmfPkg/Library/VirtioLib/VirtioLib.c                         | 5 +++++
>>>>  OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c       | 5 +++++
>>>>  OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockServiceDxe.c    | 5 +++++
>>>>  OvmfPkg/SataControllerDxe/SataController.c                    | 5 +++++
>>>>  OvmfPkg/VirtioGpuDxe/Gop.c                                    | 6 ++++++
>>>>  OvmfPkg/VirtioNetDxe/SnpReceive.c                             | 5 +++++
>>>>  9 files changed, 45 insertions(+)
>>>>
>>>> diff --git a/OvmfPkg/AcpiPlatformDxe/Xen.c b/OvmfPkg/AcpiPlatformDxe/Xen.c
>>>> index 357c60d23f4e..c8f275a8ee84 100644
>>>> --- a/OvmfPkg/AcpiPlatformDxe/Xen.c
>>>> +++ b/OvmfPkg/AcpiPlatformDxe/Xen.c
>>>> @@ -144,16 +144,21 @@ InstallXenTables (
>>>>    Fadt2Table  = NULL;
>>>>    Fadt1Table  = NULL;
>>>>    Facs2Table  = NULL;
>>>>    Facs1Table  = NULL;
>>>>    DsdtTable   = NULL;
>>>>    TableHandle = 0;
>>>>    NumberOfTableEntries = 0;
>>>>
>>>> +  //
>>>> +  // Suppress "Value stored to ... is never read" analyzer warnings.
>>>> +  //
>>>> +  (VOID)NumberOfTableEntries;
>>>> +
>>>
>>> I've seen this solution to shut up the compiler for similar reasons,
>>> and it kind of bugs me.
>>>
>>> It looks like both paths of the if & else initialize
>>> NumberOfTableEntries, so maybe we can just drop setting it to 0?
>>
>> It might trigger *other* compilers to whine about "variable read
>> without initialization" :)
>>
>>> I looked at FwhInstance too, and it doesn't look like it is used
>>> after being set. So, maybe that should just be dropped?
>>>
>>> I guess both of your bullet points give arguments allowing the
>>> unused set.
>>>
>>> Rather than adding "Suppress..." comments everywhere, maybe a global
>>> macro could be defined for similar uses in EDK II?
>>>
>>> //
>>> // Suppress "Value stored to ... is never read" analyzer warnings.
>>> //
>>> #define IGNORE_UNUSED_ASSIGNMENT(var) ((VOID)var)
>>>
>>> Then again, I guess we decided to suppress this in EDK II compiler
>>> warnings with -Wno-unused-but-set-variable.
>>>
>>> So, can you adjust the RH covscan tool settings to similarly ignore
>>> these warnings?
>>
>> I think that should be possible, yes. AIUI it is supposed to have
>> location-sensitive permanent overrides (maintained outside of the
>> source code), and it should be doing incremental / differential
>> scanning -- report only "new" issues.
>
> I think if the setting can be tweaked, maybe most of these changes
> wouldn't be needed. But, it also might prevent you from having to
> "fix" similar issues in the future.

Can you please go through the series one by one, and suggest
individually which patches should be dropped?


>> Admittedly, I hate most of the warning suppression patches myself,
>> littering our code -- and that applies to all the *historical*
>> spurious assignments that we already have in place --, so I'm 100%
>> fine with dropping this patch (and other suppression patches too, if
>> that is the upstream edk2 project's preference!)
>
> In MdePkg/Include/X64/ProcessorBind.h, I see:
>
> //
> // Disable ICC's remark #593: "Variable" was set but never used.
> // This is legal ANSI C code so we disable the remark that is turned on with /W4
> //
> #pragma warning ( disable : 593 )
>
> And, then we have -Wno-unused-but-set-variable for GCC.
>
> Regarding "spurious assignments", MdePkg/Include/X64/ProcessorBind.h,
> I also see:
>
> //
> // This warning is for potentially uninitialized local variable, and it may cause false
> // positive issues in VS2013 and VS2015 build
> //
> #pragma warning ( disable : 4701 )

It's great when warnings can be tweaked with such resolution, at the
category level. There are two counter-arguments.

- Regarding "potentially uninitialized local variable", we could have
  globally disabled "-Wmaybe-uninitialized" under GCC. The decision not
  to do that was conscious -- apparently we prefer adding the
  zero-assignments manually, and getting a few valid warnings in
  exchange, to not getting any such warnings (valid or invalid). We only
  suppress the warning for external projects (OpenSSL and Oniguruma).

  Admittedly, it's not clear to me why the VS2013/VS2015 approach
  *differs* from the GCC approach -- but that too could be justified, if
  VS emitted an unbearable amount of false positives. I'm not sure.

- The other argument against such category-level tweaking is that
  clang's *analyzer* (not the base compiler) simply doesn't offer it,
  according to its documentation. (Please see more details below.)

So here's my opinion on each patch:

> 1  5b84fae949ec MdePkg/PiFirmwareFile: express IS_SECTION2 in terms of SECTION_SIZE

Just a refactoring, so that the next patch fixes IS_SECTION2() at once.
We should keep it.

> 2  937afaeb7349 MdePkg/PiFirmwareFile: fix undefined behavior in SECTION_SIZE

I think we should keep this, as-is. The warning is justified, and IMO
the patch uses well-defined behavior.

> 3  23c61ae8b546 BaseTools/PiFirmwareFile: fix undefined behavior in SECTION_SIZE

Reflects the previous fix to BaseTools; we should keep it.

> 4  f1ff9add5f9e MdePkg/PiFirmwareFile: fix undefined behavior in FFS_FILE_SIZE

Valid warning, we should keep the patch.

> 5  28ec922c05b3 OvmfPkg/Sec: fix out-of-bounds reads

Valid warning, fix the issue by using the now-fixed SECTION_SIZE /
FFS_FILE_SIZE.

> 6  474482564fee OvmfPkg/QemuVideoDxe: avoid arithmetic on null pointer

Valid warning, we should keep the patch.

> 7  28d72e8d441e OvmfPkg/AcpiPlatformDxe: suppress invalid "deref of undef pointer" warning

False positive from clang-analyzer.

- As I wrote in the commit message, the direct report ("Dereference of
  undefined pointer value") can be suppressed, as first step, with a
  NULL assignment. This is something we tend to do anyway, because edk2
  toolchains as well report such false positives occasionally. However,
  the NULL-assignment only changes the report to "Dereference of null
  pointer". (See a similar example here:
  <https://bugzilla.mozilla.org/show_bug.cgi?id=712497>.)

- The latter warning (nullptr deref) is addressed by the clang-analyzer
  FAQ: <https://clang-analyzer.llvm.org/faq.html#null_pointer>

I'm fine dropping this patch (and suppressing it, based on source code
location, in RH covscan), but I don't think clang-analyzer itself offers
any pragma or option to suppress the warning category.

> 8  46ee37494741 OvmfPkg: suppress "Value stored to ... is never read" analyzer warnings

I would *definitely* suppress this warning globally, if clang-analyzer
made that possible. It's not possible however:
<https://clang-analyzer.llvm.org/faq.html#dead_store>. It only talks
about "specific" dead stores, and ((void)x) as a workaround.

See also:

- https://clang-analyzer.llvm.org/faq.html#suppress_issue
- https://clang-analyzer.llvm.org/faq.html#exclude_code

> Q: How can I suppress a specific analyzer warning?
>
> There is currently no solid mechanism for suppressing an analyzer
> warning, although this is currently being investigated. When you
> encounter an analyzer bug/false positive, check if it's one of the
> issues discussed above or if the analyzer annotations can resolve the
> issue. Second, please report it to help us improve user experience. As
> the last resort, consider using __clang_analyzer__ macro described
> below.
>
> Q: How can I selectively exclude code the analyzer examines?
>
> When the static analyzer is using clang to parse source files, it
> implicitly defines the preprocessor macro __clang_analyzer__. One can
> use this macro to selectively exclude code the analyzer examines. Here
> is an example:
>
> #ifndef __clang_analyzer__
> // Code not to be analyzed
> #endif
>
> This usage is discouraged because it makes the code dead to the
> analyzer from now on. Instead, we prefer that users file bugs against
> the analyzer when it flags false positives.

Regarding annotations
<https://clang-analyzer.llvm.org/annotations.html>, nothing seems to
apply, for suppressing dead store warnings generally.

All in all, I don't think it's possible to implement your
recommendation, in either build flags, or in "Base.h". But, again, that
doesn't mean I want to keep this patch. I'm fine dropping it an
suppressing the warning in another component (in RH covscan).

> 9  5a48ea70c227 OvmfPkg/AcpiPlatformDxe: catch theoretical nullptr deref in Xen code

This patch should be kept, as the warning is valid.

> 10  d10d8364fe7f OvmfPkg/BasePciCapLib: suppress invalid "nullptr deref" warning

False positive, we can drop the patch.


I can deal with the removal (and possibly with the reworking) of
individual patches; what I can not deal with is general / sweeping
control over clang-analyzer's warning categories. The clang-analyzer
project appears opposed to that approach (based on their FAQ).

Please mark patches individually that you'd like me to drop.

Thanks!
Laszlo

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [edk2-devel] [PATCH 02/10] MdePkg/PiFirmwareFile: fix undefined behavior in SECTION_SIZE
  2019-04-16 10:59         ` Laszlo Ersek
@ 2019-04-16 16:50           ` Philippe Mathieu-Daudé
  2019-04-17 10:08             ` Laszlo Ersek
  2019-04-16 18:48           ` Jordan Justen
  1 sibling, 1 reply; 52+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-04-16 16:50 UTC (permalink / raw)
  To: devel, lersek, Jordan Justen, Michael D Kinney; +Cc: Liming Gao

Hi Laszlo,

On 4/16/19 12:59 PM, Laszlo Ersek wrote:
> On 04/16/19 11:04, Jordan Justen wrote:
>> On 2019-04-15 09:15:31, Laszlo Ersek wrote:
>>> On 04/14/19 09:19, Jordan Justen wrote:
>>>> On 2019-04-12 16:31:20, Laszlo Ersek wrote:
>>>>> RH covscan justifiedly reports that accessing
>>>>> "EFI_COMMON_SECTION_HEADER.Size", which is of type UINT8[3], through a
>>>>> (UINT32*), is undefined behavior:
>>>>>
>>>>>> Error: OVERRUN (CWE-119):
>>>>>> edk2-89910a39dcfd/OvmfPkg/Sec/SecMain.c:178: overrun-local: Overrunning
>>>>>> array of 3 bytes at byte offset 3 by dereferencing pointer
>>>>>> "(UINT32 *)((EFI_COMMON_SECTION_HEADER *)(UINTN)Section)->Size".
>>>>>> #  176|       Section = (EFI_COMMON_SECTION_HEADER*)(UINTN) CurrentAddress;
>>>>>> #  177|
>>>>>> #  178|->     Size = SECTION_SIZE (Section);
>>>>>> #  179|       if (Size < sizeof (*Section)) {
>>>>>> #  180|         return EFI_VOLUME_CORRUPTED;
>>>>>
>>>>> Fix this by introducing EFI_COMMON_SECTION_HEADER_UNION, and expressing
>>>>> SECTION_SIZE() in terms of "EFI_COMMON_SECTION_HEADER_UNION.Uint32".
>>>>>
>>>>> Cc: Liming Gao <liming.gao@intel.com>
>>>>> Cc: Michael D Kinney <michael.d.kinney@intel.com>
>>>>> Bugzilla: https://bugzilla.tianocore.org/show_bug.cgi?id=1710
>>>>> Issue: scan-1007.txt
>>>>> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
>>>>> ---
>>>>>  MdePkg/Include/Pi/PiFirmwareFile.h | 10 +++++++++-
>>>>>  1 file changed, 9 insertions(+), 1 deletion(-)
>>>>>
>>>>> diff --git a/MdePkg/Include/Pi/PiFirmwareFile.h b/MdePkg/Include/Pi/PiFirmwareFile.h
>>>>> index a9f3bcc4eb8e..4fce8298d1c0 100644
>>>>> --- a/MdePkg/Include/Pi/PiFirmwareFile.h
>>>>> +++ b/MdePkg/Include/Pi/PiFirmwareFile.h
>>>>> @@ -229,16 +229,24 @@ typedef struct {
>>>>>    ///
>>>>>    UINT8             Size[3];
>>>>>    EFI_SECTION_TYPE  Type;
>>>>>    ///
>>>>>    /// Declares the section type.
>>>>>    ///
>>>>>  } EFI_COMMON_SECTION_HEADER;
>>>>>  
>>>>> +///
>>>>> +/// Union that permits accessing EFI_COMMON_SECTION_HEADER as a UINT32 object.
>>>>> +///
>>>>> +typedef union {
>>>>> +  EFI_COMMON_SECTION_HEADER Hdr;
>>>>> +  UINT32                    Uint32;
>>>>> +} EFI_COMMON_SECTION_HEADER_UNION;
>>>>> +
>>>>>  typedef struct {
>>>>>    ///
>>>>>    /// A 24-bit unsigned integer that contains the total size of the section in bytes,
>>>>>    /// including the EFI_COMMON_SECTION_HEADER.
>>>>>    ///
>>>>>    UINT8             Size[3];
>>>>>  
>>>>>    EFI_SECTION_TYPE  Type;
>>>>> @@ -476,17 +484,17 @@ typedef struct {
>>>>>    /// A UINT16 that represents a particular build. Subsequent builds have monotonically
>>>>>    /// increasing build numbers relative to earlier builds.
>>>>>    ///
>>>>>    UINT16                        BuildNumber;
>>>>>    CHAR16                        VersionString[1];
>>>>>  } EFI_VERSION_SECTION2;
>>>>>  
>>>>>  #define SECTION_SIZE(SectionHeaderPtr) \
>>>>> -    ((UINT32) (*((UINT32 *) ((EFI_COMMON_SECTION_HEADER *) (UINTN) SectionHeaderPtr)->Size) & 0x00ffffff))
>>>>> +    (((EFI_COMMON_SECTION_HEADER_UNION *) (UINTN) (SectionHeaderPtr))->Uint32 & 0x00ffffff)
>>>>
>>>> Mike, all,
>>>>
>>>> Can we add a typedef for EFI_COMMON_SECTION_HEADER_UNION if it's not
>>>> in the PI spec?
>>>>
>>>> If it's not allowed, I think something like this might work too:
>>>>
>>>> #define SECTION_SIZE(SectionHeaderPtr) \
>>>>     (*((UINT32*)(UINTN)(SectionHeaderPtr)) & 0x00ffffff)
>>>
>>> (Less importantly:)
>>>
>>> It might shut up the static analyzer, but regarding the C standard, it's
>>> equally undefined behavior.
>>
>> I think you are still accessing it through a UINT32*, since you are
>> using a pointer to a union, and an field of type UINT32 within the
>> union.
> 
> Using a union makes the behavior well-defined.
> 
>> 6.2.7 Compatible type and composite type
>>
>> 1 Two types have compatible type if their types are the same.
>>   Additional rules for determining whether two types are compatible
>>   are described in [...]
> 
>> 6.5 Expressions
>>
>> 6 The /effective type/ of an object for an access to its stored value
>>   is the declared type of the object, if any. [...]
>>
>> 7 An object shall have its stored value accessed only by an lvalue
>>   expression that has one of the following types:
>>
>>   — a type compatible with the effective type of the object,
>>   — a qualified version of a type compatible with the effective type
>>     of the object,
>>   — a type that is the signed or unsigned type corresponding to the
>>     effective type of the object,
>>   — a type that is the signed or unsigned type corresponding to a
>>     qualified version of the effective type of the object,
>>   — an aggregate or union type that includes one of the aforementioned
>>     types among its members (including, recursively, a member of a
>>     subaggregate or contained union), or
>>   — a character type.
> 
> - Regarding 6.5p6, the original object we intend to access has
> (declared) type EFI_COMMON_SECTION_HEADER. Therefore the effective type
> is EFI_COMMON_SECTION_HEADER.
> 
> - Based on 6.2.7p1, EFI_COMMON_SECTION_HEADER is compatible with
> EFI_COMMON_SECTION_HEADER. (Because they are the same.)
> 
> - Based on 6.5p7 item #5, EFI_COMMON_SECTION_HEADER can be accessed as
> EFI_COMMON_SECTION_HEADER_UNION, because EFI_COMMON_SECTION_HEADER_UNION
> includes "a type compatible with the effective type of the object" (#1)
> among its members -- namely an EFI_COMMON_SECTION_HEADER, which is
> compatible with EFI_COMMON_SECTION_HEADER, because they are the same.
> 
>> I guess it might more well defined to shift the bytes, like is
>> sometimes done with the FFS file sizes.
> 
> I did that (i.e. byte-shifting) in the other patch:
> 
>   [edk2-devel] [PATCH 04/10]
>   MdePkg/PiFirmwareFile: fix undefined behavior in FFS_FILE_SIZE
> 
> but for SECTION_SIZE, the union is well-defined too.

Why not use a 8-bit access macro similar to FFS_FILE_SIZE(), the one you
added in patch 4/10 of this series?

> 
> Thanks,
> Laszlo
> 
>>
>> -Jordan
>>
>>> Anyway I don't feel too strongly about this, given that we disable the
>>> strict aliasing / effective type rules in "tools_def.template"
>>> ("-fno-strict-aliasing").
>>>
>>>> Then again, I see SECTION_SIZE is not in the spec, so maybe it's ok to
>>>> add the typedef.
>>>
>>> (More importantly:)
>>>
>>> Indeed the doubt you voice about ..._UNION crossed my mind, but then I
>>> too searched the PI spec for SECTION_SIZE, with no hits.
>>>
>>> Beyond that, I searched both the PI and UEFI specs, for "_UNION" --
>>> again no hits, despite our definitions of:
>>>
>>> - EFI_IMAGE_OPTIONAL_HEADER_UNION
>>> - EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION
>>>
>>> in
>>>
>>> - "MdePkg/Include/IndustryStandard/PeImage.h"
>>> - "MdePkg/Include/Protocol/GraphicsOutput.h"
>>>
>>> respectively.
>>>
>>> Thanks,
>>> Laszlo
>>>
>>>>
>>>> -Jordan
>>>>
>>>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [edk2-devel] [PATCH 02/10] MdePkg/PiFirmwareFile: fix undefined behavior in SECTION_SIZE
  2019-04-16 10:59         ` Laszlo Ersek
  2019-04-16 16:50           ` Philippe Mathieu-Daudé
@ 2019-04-16 18:48           ` Jordan Justen
  2019-04-16 23:25             ` Andrew Fish
  2019-04-17 10:01             ` Laszlo Ersek
  1 sibling, 2 replies; 52+ messages in thread
From: Jordan Justen @ 2019-04-16 18:48 UTC (permalink / raw)
  To: Laszlo Ersek, Michael D Kinney, edk2-devel-groups-io; +Cc: Liming Gao

On 2019-04-16 03:59:48, Laszlo Ersek wrote:
> On 04/16/19 11:04, Jordan Justen wrote:
> > On 2019-04-15 09:15:31, Laszlo Ersek wrote:
> >> On 04/14/19 09:19, Jordan Justen wrote:
> >>> On 2019-04-12 16:31:20, Laszlo Ersek wrote:
> >>>> RH covscan justifiedly reports that accessing
> >>>> "EFI_COMMON_SECTION_HEADER.Size", which is of type UINT8[3], through a
> >>>> (UINT32*), is undefined behavior:
> >>>>
> >>>>> Error: OVERRUN (CWE-119):
> >>>>> edk2-89910a39dcfd/OvmfPkg/Sec/SecMain.c:178: overrun-local: Overrunning
> >>>>> array of 3 bytes at byte offset 3 by dereferencing pointer
> >>>>> "(UINT32 *)((EFI_COMMON_SECTION_HEADER *)(UINTN)Section)->Size".
> >>>>> #  176|       Section = (EFI_COMMON_SECTION_HEADER*)(UINTN) CurrentAddress;
> >>>>> #  177|
> >>>>> #  178|->     Size = SECTION_SIZE (Section);
> >>>>> #  179|       if (Size < sizeof (*Section)) {
> >>>>> #  180|         return EFI_VOLUME_CORRUPTED;
> >>>>
> >>>> Fix this by introducing EFI_COMMON_SECTION_HEADER_UNION, and expressing
> >>>> SECTION_SIZE() in terms of "EFI_COMMON_SECTION_HEADER_UNION.Uint32".
> >>>>
> >>>> Cc: Liming Gao <liming.gao@intel.com>
> >>>> Cc: Michael D Kinney <michael.d.kinney@intel.com>
> >>>> Bugzilla: https://bugzilla.tianocore.org/show_bug.cgi?id=1710
> >>>> Issue: scan-1007.txt
> >>>> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> >>>> ---
> >>>>  MdePkg/Include/Pi/PiFirmwareFile.h | 10 +++++++++-
> >>>>  1 file changed, 9 insertions(+), 1 deletion(-)
> >>>>
> >>>> diff --git a/MdePkg/Include/Pi/PiFirmwareFile.h b/MdePkg/Include/Pi/PiFirmwareFile.h
> >>>> index a9f3bcc4eb8e..4fce8298d1c0 100644
> >>>> --- a/MdePkg/Include/Pi/PiFirmwareFile.h
> >>>> +++ b/MdePkg/Include/Pi/PiFirmwareFile.h
> >>>> @@ -229,16 +229,24 @@ typedef struct {
> >>>>    ///
> >>>>    UINT8             Size[3];
> >>>>    EFI_SECTION_TYPE  Type;
> >>>>    ///
> >>>>    /// Declares the section type.
> >>>>    ///
> >>>>  } EFI_COMMON_SECTION_HEADER;
> >>>>  
> >>>> +///
> >>>> +/// Union that permits accessing EFI_COMMON_SECTION_HEADER as a UINT32 object.
> >>>> +///
> >>>> +typedef union {
> >>>> +  EFI_COMMON_SECTION_HEADER Hdr;
> >>>> +  UINT32                    Uint32;
> >>>> +} EFI_COMMON_SECTION_HEADER_UNION;
> >>>> +
> >>>>  typedef struct {
> >>>>    ///
> >>>>    /// A 24-bit unsigned integer that contains the total size of the section in bytes,
> >>>>    /// including the EFI_COMMON_SECTION_HEADER.
> >>>>    ///
> >>>>    UINT8             Size[3];
> >>>>  
> >>>>    EFI_SECTION_TYPE  Type;
> >>>> @@ -476,17 +484,17 @@ typedef struct {
> >>>>    /// A UINT16 that represents a particular build. Subsequent builds have monotonically
> >>>>    /// increasing build numbers relative to earlier builds.
> >>>>    ///
> >>>>    UINT16                        BuildNumber;
> >>>>    CHAR16                        VersionString[1];
> >>>>  } EFI_VERSION_SECTION2;
> >>>>  
> >>>>  #define SECTION_SIZE(SectionHeaderPtr) \
> >>>> -    ((UINT32) (*((UINT32 *) ((EFI_COMMON_SECTION_HEADER *) (UINTN) SectionHeaderPtr)->Size) & 0x00ffffff))
> >>>> +    (((EFI_COMMON_SECTION_HEADER_UNION *) (UINTN) (SectionHeaderPtr))->Uint32 & 0x00ffffff)
> >>>
> >>> Mike, all,
> >>>
> >>> Can we add a typedef for EFI_COMMON_SECTION_HEADER_UNION if it's not
> >>> in the PI spec?
> >>>
> >>> If it's not allowed, I think something like this might work too:
> >>>
> >>> #define SECTION_SIZE(SectionHeaderPtr) \
> >>>     (*((UINT32*)(UINTN)(SectionHeaderPtr)) & 0x00ffffff)
> >>
> >> (Less importantly:)
> >>
> >> It might shut up the static analyzer, but regarding the C standard, it's
> >> equally undefined behavior.
> > 
> > I think you are still accessing it through a UINT32*, since you are
> > using a pointer to a union, and an field of type UINT32 within the
> > union.
> 
> Using a union makes the behavior well-defined.
> 
> > 6.2.7 Compatible type and composite type
> >
> > 1 Two types have compatible type if their types are the same.
> >   Additional rules for determining whether two types are compatible
> >   are described in [...]
> 
> > 6.5 Expressions
> >
> > 6 The /effective type/ of an object for an access to its stored value
> >   is the declared type of the object, if any. [...]
> >
> > 7 An object shall have its stored value accessed only by an lvalue
> >   expression that has one of the following types:

I think maybe this all applies to lvalues, not rvalues. The boon and
bane of C is that any pointer can be easily cast to a pointer of any
other type and then dereferenced.

If the pointer is dereferenced to a type that is larger, then I
understand that there are cases where deferencing the pointer could
have unintended side effects, but that is not the case here.

The dereference could also be undefined if big-endian was in the
picture, but UEFI restricts that.

Of course none of this stops a tool from trying to delve further into
the pointer usage to look for possible issues.

But, I don't see how any of this changes the fact that with or without
the union, we are dereferencing a UINT32 pointer.

-Jordan

> >
> >   \u2014 a type compatible with the effective type of the object,
> >   \u2014 a qualified version of a type compatible with the effective type
> >     of the object,
> >   \u2014 a type that is the signed or unsigned type corresponding to the
> >     effective type of the object,
> >   \u2014 a type that is the signed or unsigned type corresponding to a
> >     qualified version of the effective type of the object,
> >   \u2014 an aggregate or union type that includes one of the aforementioned
> >     types among its members (including, recursively, a member of a
> >     subaggregate or contained union), or
> >   \u2014 a character type.
> 
> - Regarding 6.5p6, the original object we intend to access has
> (declared) type EFI_COMMON_SECTION_HEADER. Therefore the effective type
> is EFI_COMMON_SECTION_HEADER.
> 
> - Based on 6.2.7p1, EFI_COMMON_SECTION_HEADER is compatible with
> EFI_COMMON_SECTION_HEADER. (Because they are the same.)
> 
> - Based on 6.5p7 item #5, EFI_COMMON_SECTION_HEADER can be accessed as
> EFI_COMMON_SECTION_HEADER_UNION, because EFI_COMMON_SECTION_HEADER_UNION
> includes "a type compatible with the effective type of the object" (#1)
> among its members -- namely an EFI_COMMON_SECTION_HEADER, which is
> compatible with EFI_COMMON_SECTION_HEADER, because they are the same.
> 
> > I guess it might more well defined to shift the bytes, like is
> > sometimes done with the FFS file sizes.
> 
> I did that (i.e. byte-shifting) in the other patch:
> 
>   [edk2-devel] [PATCH 04/10]
>   MdePkg/PiFirmwareFile: fix undefined behavior in FFS_FILE_SIZE
> 
> but for SECTION_SIZE, the union is well-defined too.
> 
> Thanks,
> Laszlo
> 
> > 
> > -Jordan
> > 
> >> Anyway I don't feel too strongly about this, given that we disable the
> >> strict aliasing / effective type rules in "tools_def.template"
> >> ("-fno-strict-aliasing").
> >>
> >>> Then again, I see SECTION_SIZE is not in the spec, so maybe it's ok to
> >>> add the typedef.
> >>
> >> (More importantly:)
> >>
> >> Indeed the doubt you voice about ..._UNION crossed my mind, but then I
> >> too searched the PI spec for SECTION_SIZE, with no hits.
> >>
> >> Beyond that, I searched both the PI and UEFI specs, for "_UNION" --
> >> again no hits, despite our definitions of:
> >>
> >> - EFI_IMAGE_OPTIONAL_HEADER_UNION
> >> - EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION
> >>
> >> in
> >>
> >> - "MdePkg/Include/IndustryStandard/PeImage.h"
> >> - "MdePkg/Include/Protocol/GraphicsOutput.h"
> >>
> >> respectively.
> >>
> >> Thanks,
> >> Laszlo
> >>
> >>>
> >>> -Jordan
> >>>
> >>
> 

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [edk2-devel] [PATCH 02/10] MdePkg/PiFirmwareFile: fix undefined behavior in SECTION_SIZE
  2019-04-16 18:48           ` Jordan Justen
@ 2019-04-16 23:25             ` Andrew Fish
  2019-04-17 10:29               ` Laszlo Ersek
  2019-04-17 10:01             ` Laszlo Ersek
  1 sibling, 1 reply; 52+ messages in thread
From: Andrew Fish @ 2019-04-16 23:25 UTC (permalink / raw)
  To: devel, Jordan Justen; +Cc: Laszlo Ersek, Mike Kinney, Liming Gao

[-- Attachment #1: Type: text/plain, Size: 12315 bytes --]



> On Apr 16, 2019, at 11:48 AM, Jordan Justen <jordan.l.justen@intel.com> wrote:
> 
> On 2019-04-16 03:59:48, Laszlo Ersek wrote:
>> On 04/16/19 11:04, Jordan Justen wrote:
>>> On 2019-04-15 09:15:31, Laszlo Ersek wrote:
>>>> On 04/14/19 09:19, Jordan Justen wrote:
>>>>> On 2019-04-12 16:31:20, Laszlo Ersek wrote:
>>>>>> RH covscan justifiedly reports that accessing
>>>>>> "EFI_COMMON_SECTION_HEADER.Size", which is of type UINT8[3], through a
>>>>>> (UINT32*), is undefined behavior:
>>>>>> 
>>>>>>> Error: OVERRUN (CWE-119):
>>>>>>> edk2-89910a39dcfd/OvmfPkg/Sec/SecMain.c:178: overrun-local: Overrunning
>>>>>>> array of 3 bytes at byte offset 3 by dereferencing pointer
>>>>>>> "(UINT32 *)((EFI_COMMON_SECTION_HEADER *)(UINTN)Section)->Size".
>>>>>>> #  176|       Section = (EFI_COMMON_SECTION_HEADER*)(UINTN) CurrentAddress;
>>>>>>> #  177|
>>>>>>> #  178|->     Size = SECTION_SIZE (Section);
>>>>>>> #  179|       if (Size < sizeof (*Section)) {
>>>>>>> #  180|         return EFI_VOLUME_CORRUPTED;
>>>>>> 
>>>>>> Fix this by introducing EFI_COMMON_SECTION_HEADER_UNION, and expressing
>>>>>> SECTION_SIZE() in terms of "EFI_COMMON_SECTION_HEADER_UNION.Uint32".
>>>>>> 
>>>>>> Cc: Liming Gao <liming.gao@intel.com>
>>>>>> Cc: Michael D Kinney <michael.d.kinney@intel.com>
>>>>>> Bugzilla: https://bugzilla.tianocore.org/show_bug.cgi?id=1710
>>>>>> Issue: scan-1007.txt
>>>>>> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
>>>>>> ---
>>>>>> MdePkg/Include/Pi/PiFirmwareFile.h | 10 +++++++++-
>>>>>> 1 file changed, 9 insertions(+), 1 deletion(-)
>>>>>> 
>>>>>> diff --git a/MdePkg/Include/Pi/PiFirmwareFile.h b/MdePkg/Include/Pi/PiFirmwareFile.h
>>>>>> index a9f3bcc4eb8e..4fce8298d1c0 100644
>>>>>> --- a/MdePkg/Include/Pi/PiFirmwareFile.h
>>>>>> +++ b/MdePkg/Include/Pi/PiFirmwareFile.h
>>>>>> @@ -229,16 +229,24 @@ typedef struct {
>>>>>>   ///
>>>>>>   UINT8             Size[3];
>>>>>>   EFI_SECTION_TYPE  Type;
>>>>>>   ///
>>>>>>   /// Declares the section type.
>>>>>>   ///
>>>>>> } EFI_COMMON_SECTION_HEADER;
>>>>>> 
>>>>>> +///
>>>>>> +/// Union that permits accessing EFI_COMMON_SECTION_HEADER as a UINT32 object.
>>>>>> +///
>>>>>> +typedef union {
>>>>>> +  EFI_COMMON_SECTION_HEADER Hdr;
>>>>>> +  UINT32                    Uint32;
>>>>>> +} EFI_COMMON_SECTION_HEADER_UNION;
>>>>>> +
>>>>>> typedef struct {
>>>>>>   ///
>>>>>>   /// A 24-bit unsigned integer that contains the total size of the section in bytes,
>>>>>>   /// including the EFI_COMMON_SECTION_HEADER.
>>>>>>   ///
>>>>>>   UINT8             Size[3];
>>>>>> 
>>>>>>   EFI_SECTION_TYPE  Type;
>>>>>> @@ -476,17 +484,17 @@ typedef struct {
>>>>>>   /// A UINT16 that represents a particular build. Subsequent builds have monotonically
>>>>>>   /// increasing build numbers relative to earlier builds.
>>>>>>   ///
>>>>>>   UINT16                        BuildNumber;
>>>>>>   CHAR16                        VersionString[1];
>>>>>> } EFI_VERSION_SECTION2;
>>>>>> 
>>>>>> #define SECTION_SIZE(SectionHeaderPtr) \
>>>>>> -    ((UINT32) (*((UINT32 *) ((EFI_COMMON_SECTION_HEADER *) (UINTN) SectionHeaderPtr)->Size) & 0x00ffffff))
>>>>>> +    (((EFI_COMMON_SECTION_HEADER_UNION *) (UINTN) (SectionHeaderPtr))->Uint32 & 0x00ffffff)
>>>>> 
>>>>> Mike, all,
>>>>> 
>>>>> Can we add a typedef for EFI_COMMON_SECTION_HEADER_UNION if it's not
>>>>> in the PI spec?
>>>>> 
>>>>> If it's not allowed, I think something like this might work too:
>>>>> 
>>>>> #define SECTION_SIZE(SectionHeaderPtr) \
>>>>>    (*((UINT32*)(UINTN)(SectionHeaderPtr)) & 0x00ffffff)
>>>> 
>>>> (Less importantly:)
>>>> 
>>>> It might shut up the static analyzer, but regarding the C standard, it's
>>>> equally undefined behavior.
>>> 
>>> I think you are still accessing it through a UINT32*, since you are
>>> using a pointer to a union, and an field of type UINT32 within the
>>> union.
>> 
>> Using a union makes the behavior well-defined.
>> 
>>> 6.2.7 Compatible type and composite type
>>> 
>>> 1 Two types have compatible type if their types are the same.
>>>  Additional rules for determining whether two types are compatible
>>>  are described in [...]
>> 
>>> 6.5 Expressions
>>> 
>>> 6 The /effective type/ of an object for an access to its stored value
>>>  is the declared type of the object, if any. [...]
>>> 
>>> 7 An object shall have its stored value accessed only by an lvalue
>>>  expression that has one of the following types:
> 
> I think maybe this all applies to lvalues, not rvalues. The boon and
> bane of C is that any pointer can be easily cast to a pointer of any
> other type and then dereferenced.
> 
> If the pointer is dereferenced to a type that is larger, then I
> understand that there are cases where deferencing the pointer could
> have unintended side effects, but that is not the case here.
> 
> The dereference could also be undefined if big-endian was in the
> picture, but UEFI restricts that.
> 
> Of course none of this stops a tool from trying to delve further into
> the pointer usage to look for possible issues.
> 
> But, I don't see how any of this changes the fact that with or without
> the union, we are dereferencing a UINT32 pointer.
> 

The thing that is really saving us is the 4 byte alignment requirement for FV sections in the PI Spec, but that is not expressed by EFI_COMMON_SECTION_HEADER to the compiler. The union is better as it enforces alignment of the structure. This enforced alignment is likely what makes static analysis tools happy. 

I don't think the casting in the existing SECTION_SIZE is UB (Undefined Behavior) as the extraction is not the issue as you are telling the compiler to extract 4 unaligned bytes. That is the same as accessing a packed structure. But this is only because you started with a byte pointer so you are not really violating any C alignment rules. Thus in a case like our cast, or pragma pack(1),  the compiler has extra alignment info provided so all is good, the issue is if you assign a pointer into the type the only alignment info the compiler has is the rules for that type, and non of packing rules. A lot of the above C rules are making it clear what the compiler does in these cases. 

Ironically the new union macro is undefined behavior at runtime during the cast if the section header is not 4 byte algined since you did not start with something (unsigned char pointer) that allowed byte access. See my example of the ubsan fault. 

The nice thing about the union is it tells the compiler our intended constraint from the PI spec. 

// This 5 byte structure will align EFI_COMMON_SECTION_HEADER on an odd byte boundary. 
typedef struct {
  UINT8                     Count;
  EFI_COMMON_SECTION_HEADER Sec;
} UNALIGNED_SECTION_HEADER;

// This will properly align EFI_COMMON_SECTION_HEADER_UNION on a 4 byte boundary. 
typedef struct {
  UINT8                           Count;
  EFI_COMMON_SECTION_HEADER_UNION Sec;
} ALIGNED_SECTION_HEADER2;

I tried to validate this with the clang ubsan... The only runtime UB was the new macro against UNALIGNED_SECTION_HEADER. ALIGNED_SECTION_HEADER2 with the new union aligned everything correctly and works fine. 

./a.out
Fv.c:55:11: runtime error: member access within misaligned address 0x000104b23021 for type 'EFI_COMMON_SECTION_HEADER_UNION', which requires 4 byte alignment
0x000104b23021: note: pointer points here
 00 00 00  ff 01 02 03 10 00 00 00  aa 00 00 00 01 02 03 10  2a 2f b2 04 01 00 00 00  34 00 00 00 0d
              ^ 
Fv.c:55:11: runtime error: load of misaligned address 0x000104b23021 for type 'UINT32' (aka 'unsigned int'), which requires 4 byte alignment
0x000104b23021: note: pointer points here
 00 00 00  ff 01 02 03 10 00 00 00  aa 00 00 00 01 02 03 10  2a 2f b2 04 01 00 00 00  34 00 00 00 0d
              ^ 

$ clang -fsanitize=undefined Fv.c
$ cat Fv.c
typedef unsigned char       UINT8;
typedef UINT8               EFI_SECTION_TYPE;
typedef unsigned int        UINT32;
typedef unsigned long long  UINTN;

typedef UINT8 EFI_SECTION_TYPE;

///
/// Common section header.
/// 
typedef struct {
  ///
  /// A 24-bit unsigned integer that contains the total size of the section in bytes, 
  /// including the EFI_COMMON_SECTION_HEADER.
  ///
  UINT8             Size[3];
  EFI_SECTION_TYPE  Type;
  ///
  /// Declares the section type.
  ///
} EFI_COMMON_SECTION_HEADER;

typedef union {
  EFI_COMMON_SECTION_HEADER Hdr;
  UINT32                    Uint32;
} EFI_COMMON_SECTION_HEADER_UNION;


#define SECTION_SIZE(SectionHeaderPtr) \
    ((UINT32) (*((UINT32 *) ((EFI_COMMON_SECTION_HEADER *) (UINTN) SectionHeaderPtr)->Size) & 0x00ffffff))

#define SECTION_SIZE2(SectionHeaderPtr) \
    (((EFI_COMMON_SECTION_HEADER_UNION *) (UINTN) (SectionHeaderPtr))->Uint32 & 0x00ffffff)


typedef struct {
  UINT8                     Count;
  EFI_COMMON_SECTION_HEADER Sec;
} UNALIGNED_SECTION_HEADER;

typedef struct {
  UINT8                           Count;
  EFI_COMMON_SECTION_HEADER_UNION Sec;
} ALIGNED_SECTION_HEADER2;

UNALIGNED_SECTION_HEADER  gSection  = { 0xff, { { 0x01, 0x02, 0x3 }, 0x10 } };
ALIGNED_SECTION_HEADER2   gSection2 = { 0xaa, {   } };
int
main (int argc, char **argv)
{
  UINT32 Size, Size2;
  gSection2.Sec.Uint32 = 0x10030201;
  
  Size  = SECTION_SIZE(&gSection.Sec);
  Size2 = SECTION_SIZE2(&gSection.Sec);  // runtime error:

  Size  = SECTION_SIZE(&gSection2.Sec);
  Size2 = SECTION_SIZE2(&gSection2.Sec);
  return Size == Size2;
}

Thanks,

Andrew Fish

PS If folks disagree I know a person that owns the clang ubsan architecture and sits on the C/C++ standards committees. I had a long talk with this person recently about C alignment UB and I think I understand it a little better from the compiler point of view now. 

> -Jordan
> 
>>> 
>>>  \u2014 a type compatible with the effective type of the object,
>>>  \u2014 a qualified version of a type compatible with the effective type
>>>    of the object,
>>>  \u2014 a type that is the signed or unsigned type corresponding to the
>>>    effective type of the object,
>>>  \u2014 a type that is the signed or unsigned type corresponding to a
>>>    qualified version of the effective type of the object,
>>>  \u2014 an aggregate or union type that includes one of the aforementioned
>>>    types among its members (including, recursively, a member of a
>>>    subaggregate or contained union), or
>>>  \u2014 a character type.
>> 
>> - Regarding 6.5p6, the original object we intend to access has
>> (declared) type EFI_COMMON_SECTION_HEADER. Therefore the effective type
>> is EFI_COMMON_SECTION_HEADER.
>> 
>> - Based on 6.2.7p1, EFI_COMMON_SECTION_HEADER is compatible with
>> EFI_COMMON_SECTION_HEADER. (Because they are the same.)
>> 
>> - Based on 6.5p7 item #5, EFI_COMMON_SECTION_HEADER can be accessed as
>> EFI_COMMON_SECTION_HEADER_UNION, because EFI_COMMON_SECTION_HEADER_UNION
>> includes "a type compatible with the effective type of the object" (#1)
>> among its members -- namely an EFI_COMMON_SECTION_HEADER, which is
>> compatible with EFI_COMMON_SECTION_HEADER, because they are the same.
>> 
>>> I guess it might more well defined to shift the bytes, like is
>>> sometimes done with the FFS file sizes.
>> 
>> I did that (i.e. byte-shifting) in the other patch:
>> 
>>  [edk2-devel] [PATCH 04/10]
>>  MdePkg/PiFirmwareFile: fix undefined behavior in FFS_FILE_SIZE
>> 
>> but for SECTION_SIZE, the union is well-defined too.
>> 
>> Thanks,
>> Laszlo
>> 
>>> 
>>> -Jordan
>>> 
>>>> Anyway I don't feel too strongly about this, given that we disable the
>>>> strict aliasing / effective type rules in "tools_def.template"
>>>> ("-fno-strict-aliasing").
>>>> 
>>>>> Then again, I see SECTION_SIZE is not in the spec, so maybe it's ok to
>>>>> add the typedef.
>>>> 
>>>> (More importantly:)
>>>> 
>>>> Indeed the doubt you voice about ..._UNION crossed my mind, but then I
>>>> too searched the PI spec for SECTION_SIZE, with no hits.
>>>> 
>>>> Beyond that, I searched both the PI and UEFI specs, for "_UNION" --
>>>> again no hits, despite our definitions of:
>>>> 
>>>> - EFI_IMAGE_OPTIONAL_HEADER_UNION
>>>> - EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION
>>>> 
>>>> in
>>>> 
>>>> - "MdePkg/Include/IndustryStandard/PeImage.h"
>>>> - "MdePkg/Include/Protocol/GraphicsOutput.h"
>>>> 
>>>> respectively.
>>>> 
>>>> Thanks,
>>>> Laszlo
>>>> 
>>>>> 
>>>>> -Jordan
>>>>> 
>>>> 
>> 
> 
> 
> 


[-- Attachment #2: Type: text/html, Size: 35329 bytes --]

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [edk2-devel] [PATCH 02/10] MdePkg/PiFirmwareFile: fix undefined behavior in SECTION_SIZE
  2019-04-16 18:48           ` Jordan Justen
  2019-04-16 23:25             ` Andrew Fish
@ 2019-04-17 10:01             ` Laszlo Ersek
  1 sibling, 0 replies; 52+ messages in thread
From: Laszlo Ersek @ 2019-04-17 10:01 UTC (permalink / raw)
  To: Jordan Justen, Michael D Kinney, edk2-devel-groups-io; +Cc: Liming Gao

On 04/16/19 20:48, Jordan Justen wrote:
> On 2019-04-16 03:59:48, Laszlo Ersek wrote:
>> On 04/16/19 11:04, Jordan Justen wrote:
>>> On 2019-04-15 09:15:31, Laszlo Ersek wrote:
>>>> On 04/14/19 09:19, Jordan Justen wrote:
>>>>> On 2019-04-12 16:31:20, Laszlo Ersek wrote:
>>>>>> RH covscan justifiedly reports that accessing
>>>>>> "EFI_COMMON_SECTION_HEADER.Size", which is of type UINT8[3], through a
>>>>>> (UINT32*), is undefined behavior:
>>>>>>
>>>>>>> Error: OVERRUN (CWE-119):
>>>>>>> edk2-89910a39dcfd/OvmfPkg/Sec/SecMain.c:178: overrun-local: Overrunning
>>>>>>> array of 3 bytes at byte offset 3 by dereferencing pointer
>>>>>>> "(UINT32 *)((EFI_COMMON_SECTION_HEADER *)(UINTN)Section)->Size".
>>>>>>> #  176|       Section = (EFI_COMMON_SECTION_HEADER*)(UINTN) CurrentAddress;
>>>>>>> #  177|
>>>>>>> #  178|->     Size = SECTION_SIZE (Section);
>>>>>>> #  179|       if (Size < sizeof (*Section)) {
>>>>>>> #  180|         return EFI_VOLUME_CORRUPTED;
>>>>>>
>>>>>> Fix this by introducing EFI_COMMON_SECTION_HEADER_UNION, and expressing
>>>>>> SECTION_SIZE() in terms of "EFI_COMMON_SECTION_HEADER_UNION.Uint32".
>>>>>>
>>>>>> Cc: Liming Gao <liming.gao@intel.com>
>>>>>> Cc: Michael D Kinney <michael.d.kinney@intel.com>
>>>>>> Bugzilla: https://bugzilla.tianocore.org/show_bug.cgi?id=1710
>>>>>> Issue: scan-1007.txt
>>>>>> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
>>>>>> ---
>>>>>>  MdePkg/Include/Pi/PiFirmwareFile.h | 10 +++++++++-
>>>>>>  1 file changed, 9 insertions(+), 1 deletion(-)
>>>>>>
>>>>>> diff --git a/MdePkg/Include/Pi/PiFirmwareFile.h b/MdePkg/Include/Pi/PiFirmwareFile.h
>>>>>> index a9f3bcc4eb8e..4fce8298d1c0 100644
>>>>>> --- a/MdePkg/Include/Pi/PiFirmwareFile.h
>>>>>> +++ b/MdePkg/Include/Pi/PiFirmwareFile.h
>>>>>> @@ -229,16 +229,24 @@ typedef struct {
>>>>>>    ///
>>>>>>    UINT8             Size[3];
>>>>>>    EFI_SECTION_TYPE  Type;
>>>>>>    ///
>>>>>>    /// Declares the section type.
>>>>>>    ///
>>>>>>  } EFI_COMMON_SECTION_HEADER;
>>>>>>  
>>>>>> +///
>>>>>> +/// Union that permits accessing EFI_COMMON_SECTION_HEADER as a UINT32 object.
>>>>>> +///
>>>>>> +typedef union {
>>>>>> +  EFI_COMMON_SECTION_HEADER Hdr;
>>>>>> +  UINT32                    Uint32;
>>>>>> +} EFI_COMMON_SECTION_HEADER_UNION;
>>>>>> +
>>>>>>  typedef struct {
>>>>>>    ///
>>>>>>    /// A 24-bit unsigned integer that contains the total size of the section in bytes,
>>>>>>    /// including the EFI_COMMON_SECTION_HEADER.
>>>>>>    ///
>>>>>>    UINT8             Size[3];
>>>>>>  
>>>>>>    EFI_SECTION_TYPE  Type;
>>>>>> @@ -476,17 +484,17 @@ typedef struct {
>>>>>>    /// A UINT16 that represents a particular build. Subsequent builds have monotonically
>>>>>>    /// increasing build numbers relative to earlier builds.
>>>>>>    ///
>>>>>>    UINT16                        BuildNumber;
>>>>>>    CHAR16                        VersionString[1];
>>>>>>  } EFI_VERSION_SECTION2;
>>>>>>  
>>>>>>  #define SECTION_SIZE(SectionHeaderPtr) \
>>>>>> -    ((UINT32) (*((UINT32 *) ((EFI_COMMON_SECTION_HEADER *) (UINTN) SectionHeaderPtr)->Size) & 0x00ffffff))
>>>>>> +    (((EFI_COMMON_SECTION_HEADER_UNION *) (UINTN) (SectionHeaderPtr))->Uint32 & 0x00ffffff)
>>>>>
>>>>> Mike, all,
>>>>>
>>>>> Can we add a typedef for EFI_COMMON_SECTION_HEADER_UNION if it's not
>>>>> in the PI spec?
>>>>>
>>>>> If it's not allowed, I think something like this might work too:
>>>>>
>>>>> #define SECTION_SIZE(SectionHeaderPtr) \
>>>>>     (*((UINT32*)(UINTN)(SectionHeaderPtr)) & 0x00ffffff)
>>>>
>>>> (Less importantly:)
>>>>
>>>> It might shut up the static analyzer, but regarding the C standard, it's
>>>> equally undefined behavior.
>>>
>>> I think you are still accessing it through a UINT32*, since you are
>>> using a pointer to a union, and an field of type UINT32 within the
>>> union.
>>
>> Using a union makes the behavior well-defined.
>>
>>> 6.2.7 Compatible type and composite type
>>>
>>> 1 Two types have compatible type if their types are the same.
>>>   Additional rules for determining whether two types are compatible
>>>   are described in [...]
>>
>>> 6.5 Expressions
>>>
>>> 6 The /effective type/ of an object for an access to its stored value
>>>   is the declared type of the object, if any. [...]
>>>
>>> 7 An object shall have its stored value accessed only by an lvalue
>>>   expression that has one of the following types:
> 
> I think maybe this all applies to lvalues, not rvalues.

Why "maybe"? The standard explicitly writes "lvalue expression" above.

And (PointerToUnion->Member) is equivalent to
((*PointerToUnion).Member); and (*PointerToUnion) is an lvalue.

> The boon and
> bane of C is that any pointer can be easily cast to a pointer of any
> other type and then dereferenced.
> 
> If the pointer is dereferenced to a type that is larger, then I
> understand that there are cases where deferencing the pointer could
> have unintended side effects, but that is not the case here.
> 
> The dereference could also be undefined if big-endian was in the
> picture, but UEFI restricts that.
> 
> Of course none of this stops a tool from trying to delve further into
> the pointer usage to look for possible issues.
> 
> But, I don't see how any of this changes the fact that with or without
> the union, we are dereferencing a UINT32 pointer.

Post-patch, we are *not* dereferencing a (UINT32*). We are dereferencing
a (EFI_COMMON_SECTION_HEADER_UNION*), and then accessing the Uint32
member in the pointed-to EFI_COMMON_SECTION_HEADER_UNION.

If we continued dereferencing a (UINT32*), then the effective type rules
that I quoted would indeed not apply. But that's not what the patch does.

Thanks
Laszlo

> 
> -Jordan
> 
>>>
>>>   \u2014 a type compatible with the effective type of the object,
>>>   \u2014 a qualified version of a type compatible with the effective type
>>>     of the object,
>>>   \u2014 a type that is the signed or unsigned type corresponding to the
>>>     effective type of the object,
>>>   \u2014 a type that is the signed or unsigned type corresponding to a
>>>     qualified version of the effective type of the object,
>>>   \u2014 an aggregate or union type that includes one of the aforementioned
>>>     types among its members (including, recursively, a member of a
>>>     subaggregate or contained union), or
>>>   \u2014 a character type.
>>
>> - Regarding 6.5p6, the original object we intend to access has
>> (declared) type EFI_COMMON_SECTION_HEADER. Therefore the effective type
>> is EFI_COMMON_SECTION_HEADER.
>>
>> - Based on 6.2.7p1, EFI_COMMON_SECTION_HEADER is compatible with
>> EFI_COMMON_SECTION_HEADER. (Because they are the same.)
>>
>> - Based on 6.5p7 item #5, EFI_COMMON_SECTION_HEADER can be accessed as
>> EFI_COMMON_SECTION_HEADER_UNION, because EFI_COMMON_SECTION_HEADER_UNION
>> includes "a type compatible with the effective type of the object" (#1)
>> among its members -- namely an EFI_COMMON_SECTION_HEADER, which is
>> compatible with EFI_COMMON_SECTION_HEADER, because they are the same.
>>
>>> I guess it might more well defined to shift the bytes, like is
>>> sometimes done with the FFS file sizes.
>>
>> I did that (i.e. byte-shifting) in the other patch:
>>
>>   [edk2-devel] [PATCH 04/10]
>>   MdePkg/PiFirmwareFile: fix undefined behavior in FFS_FILE_SIZE
>>
>> but for SECTION_SIZE, the union is well-defined too.
>>
>> Thanks,
>> Laszlo
>>
>>>
>>> -Jordan
>>>
>>>> Anyway I don't feel too strongly about this, given that we disable the
>>>> strict aliasing / effective type rules in "tools_def.template"
>>>> ("-fno-strict-aliasing").
>>>>
>>>>> Then again, I see SECTION_SIZE is not in the spec, so maybe it's ok to
>>>>> add the typedef.
>>>>
>>>> (More importantly:)
>>>>
>>>> Indeed the doubt you voice about ..._UNION crossed my mind, but then I
>>>> too searched the PI spec for SECTION_SIZE, with no hits.
>>>>
>>>> Beyond that, I searched both the PI and UEFI specs, for "_UNION" --
>>>> again no hits, despite our definitions of:
>>>>
>>>> - EFI_IMAGE_OPTIONAL_HEADER_UNION
>>>> - EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION
>>>>
>>>> in
>>>>
>>>> - "MdePkg/Include/IndustryStandard/PeImage.h"
>>>> - "MdePkg/Include/Protocol/GraphicsOutput.h"
>>>>
>>>> respectively.
>>>>
>>>> Thanks,
>>>> Laszlo
>>>>
>>>>>
>>>>> -Jordan
>>>>>
>>>>
>>


^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [edk2-devel] [PATCH 02/10] MdePkg/PiFirmwareFile: fix undefined behavior in SECTION_SIZE
  2019-04-16 16:50           ` Philippe Mathieu-Daudé
@ 2019-04-17 10:08             ` Laszlo Ersek
  0 siblings, 0 replies; 52+ messages in thread
From: Laszlo Ersek @ 2019-04-17 10:08 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, devel, Jordan Justen,
	Michael D Kinney
  Cc: Liming Gao

On 04/16/19 18:50, Philippe Mathieu-Daudé wrote:
> Hi Laszlo,
> 
> On 4/16/19 12:59 PM, Laszlo Ersek wrote:
>> On 04/16/19 11:04, Jordan Justen wrote:
>>> On 2019-04-15 09:15:31, Laszlo Ersek wrote:
>>>> On 04/14/19 09:19, Jordan Justen wrote:
>>>>> On 2019-04-12 16:31:20, Laszlo Ersek wrote:
>>>>>> RH covscan justifiedly reports that accessing
>>>>>> "EFI_COMMON_SECTION_HEADER.Size", which is of type UINT8[3], through a
>>>>>> (UINT32*), is undefined behavior:
>>>>>>
>>>>>>> Error: OVERRUN (CWE-119):
>>>>>>> edk2-89910a39dcfd/OvmfPkg/Sec/SecMain.c:178: overrun-local: Overrunning
>>>>>>> array of 3 bytes at byte offset 3 by dereferencing pointer
>>>>>>> "(UINT32 *)((EFI_COMMON_SECTION_HEADER *)(UINTN)Section)->Size".
>>>>>>> #  176|       Section = (EFI_COMMON_SECTION_HEADER*)(UINTN) CurrentAddress;
>>>>>>> #  177|
>>>>>>> #  178|->     Size = SECTION_SIZE (Section);
>>>>>>> #  179|       if (Size < sizeof (*Section)) {
>>>>>>> #  180|         return EFI_VOLUME_CORRUPTED;
>>>>>>
>>>>>> Fix this by introducing EFI_COMMON_SECTION_HEADER_UNION, and expressing
>>>>>> SECTION_SIZE() in terms of "EFI_COMMON_SECTION_HEADER_UNION.Uint32".
>>>>>>
>>>>>> Cc: Liming Gao <liming.gao@intel.com>
>>>>>> Cc: Michael D Kinney <michael.d.kinney@intel.com>
>>>>>> Bugzilla: https://bugzilla.tianocore.org/show_bug.cgi?id=1710
>>>>>> Issue: scan-1007.txt
>>>>>> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
>>>>>> ---
>>>>>>  MdePkg/Include/Pi/PiFirmwareFile.h | 10 +++++++++-
>>>>>>  1 file changed, 9 insertions(+), 1 deletion(-)
>>>>>>
>>>>>> diff --git a/MdePkg/Include/Pi/PiFirmwareFile.h b/MdePkg/Include/Pi/PiFirmwareFile.h
>>>>>> index a9f3bcc4eb8e..4fce8298d1c0 100644
>>>>>> --- a/MdePkg/Include/Pi/PiFirmwareFile.h
>>>>>> +++ b/MdePkg/Include/Pi/PiFirmwareFile.h
>>>>>> @@ -229,16 +229,24 @@ typedef struct {
>>>>>>    ///
>>>>>>    UINT8             Size[3];
>>>>>>    EFI_SECTION_TYPE  Type;
>>>>>>    ///
>>>>>>    /// Declares the section type.
>>>>>>    ///
>>>>>>  } EFI_COMMON_SECTION_HEADER;
>>>>>>  
>>>>>> +///
>>>>>> +/// Union that permits accessing EFI_COMMON_SECTION_HEADER as a UINT32 object.
>>>>>> +///
>>>>>> +typedef union {
>>>>>> +  EFI_COMMON_SECTION_HEADER Hdr;
>>>>>> +  UINT32                    Uint32;
>>>>>> +} EFI_COMMON_SECTION_HEADER_UNION;
>>>>>> +
>>>>>>  typedef struct {
>>>>>>    ///
>>>>>>    /// A 24-bit unsigned integer that contains the total size of the section in bytes,
>>>>>>    /// including the EFI_COMMON_SECTION_HEADER.
>>>>>>    ///
>>>>>>    UINT8             Size[3];
>>>>>>  
>>>>>>    EFI_SECTION_TYPE  Type;
>>>>>> @@ -476,17 +484,17 @@ typedef struct {
>>>>>>    /// A UINT16 that represents a particular build. Subsequent builds have monotonically
>>>>>>    /// increasing build numbers relative to earlier builds.
>>>>>>    ///
>>>>>>    UINT16                        BuildNumber;
>>>>>>    CHAR16                        VersionString[1];
>>>>>>  } EFI_VERSION_SECTION2;
>>>>>>  
>>>>>>  #define SECTION_SIZE(SectionHeaderPtr) \
>>>>>> -    ((UINT32) (*((UINT32 *) ((EFI_COMMON_SECTION_HEADER *) (UINTN) SectionHeaderPtr)->Size) & 0x00ffffff))
>>>>>> +    (((EFI_COMMON_SECTION_HEADER_UNION *) (UINTN) (SectionHeaderPtr))->Uint32 & 0x00ffffff)
>>>>>
>>>>> Mike, all,
>>>>>
>>>>> Can we add a typedef for EFI_COMMON_SECTION_HEADER_UNION if it's not
>>>>> in the PI spec?
>>>>>
>>>>> If it's not allowed, I think something like this might work too:
>>>>>
>>>>> #define SECTION_SIZE(SectionHeaderPtr) \
>>>>>     (*((UINT32*)(UINTN)(SectionHeaderPtr)) & 0x00ffffff)
>>>>
>>>> (Less importantly:)
>>>>
>>>> It might shut up the static analyzer, but regarding the C standard, it's
>>>> equally undefined behavior.
>>>
>>> I think you are still accessing it through a UINT32*, since you are
>>> using a pointer to a union, and an field of type UINT32 within the
>>> union.
>>
>> Using a union makes the behavior well-defined.
>>
>>> 6.2.7 Compatible type and composite type
>>>
>>> 1 Two types have compatible type if their types are the same.
>>>   Additional rules for determining whether two types are compatible
>>>   are described in [...]
>>
>>> 6.5 Expressions
>>>
>>> 6 The /effective type/ of an object for an access to its stored value
>>>   is the declared type of the object, if any. [...]
>>>
>>> 7 An object shall have its stored value accessed only by an lvalue
>>>   expression that has one of the following types:
>>>
>>>   — a type compatible with the effective type of the object,
>>>   — a qualified version of a type compatible with the effective type
>>>     of the object,
>>>   — a type that is the signed or unsigned type corresponding to the
>>>     effective type of the object,
>>>   — a type that is the signed or unsigned type corresponding to a
>>>     qualified version of the effective type of the object,
>>>   — an aggregate or union type that includes one of the aforementioned
>>>     types among its members (including, recursively, a member of a
>>>     subaggregate or contained union), or
>>>   — a character type.
>>
>> - Regarding 6.5p6, the original object we intend to access has
>> (declared) type EFI_COMMON_SECTION_HEADER. Therefore the effective type
>> is EFI_COMMON_SECTION_HEADER.
>>
>> - Based on 6.2.7p1, EFI_COMMON_SECTION_HEADER is compatible with
>> EFI_COMMON_SECTION_HEADER. (Because they are the same.)
>>
>> - Based on 6.5p7 item #5, EFI_COMMON_SECTION_HEADER can be accessed as
>> EFI_COMMON_SECTION_HEADER_UNION, because EFI_COMMON_SECTION_HEADER_UNION
>> includes "a type compatible with the effective type of the object" (#1)
>> among its members -- namely an EFI_COMMON_SECTION_HEADER, which is
>> compatible with EFI_COMMON_SECTION_HEADER, because they are the same.
>>
>>> I guess it might more well defined to shift the bytes, like is
>>> sometimes done with the FFS file sizes.
>>
>> I did that (i.e. byte-shifting) in the other patch:
>>
>>   [edk2-devel] [PATCH 04/10]
>>   MdePkg/PiFirmwareFile: fix undefined behavior in FFS_FILE_SIZE
>>
>> but for SECTION_SIZE, the union is well-defined too.
> 
> Why not use a 8-bit access macro similar to FFS_FILE_SIZE(), the one you
> added in patch 4/10 of this series?

I remain convinced that patch 02/10 (for SECTION_SIZE) is correct as it is.

That said, purely in order to put this series behind me, I'm willing to
rework SECTION_SIZE to the pattern seen in in patch 04/10
(FFS_FILE_SIZE), once Liming or Mike approves patch 04/10.

Thanks,
Laszlo

>>>> Anyway I don't feel too strongly about this, given that we disable the
>>>> strict aliasing / effective type rules in "tools_def.template"
>>>> ("-fno-strict-aliasing").
>>>>
>>>>> Then again, I see SECTION_SIZE is not in the spec, so maybe it's ok to
>>>>> add the typedef.
>>>>
>>>> (More importantly:)
>>>>
>>>> Indeed the doubt you voice about ..._UNION crossed my mind, but then I
>>>> too searched the PI spec for SECTION_SIZE, with no hits.
>>>>
>>>> Beyond that, I searched both the PI and UEFI specs, for "_UNION" --
>>>> again no hits, despite our definitions of:
>>>>
>>>> - EFI_IMAGE_OPTIONAL_HEADER_UNION
>>>> - EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION
>>>>
>>>> in
>>>>
>>>> - "MdePkg/Include/IndustryStandard/PeImage.h"
>>>> - "MdePkg/Include/Protocol/GraphicsOutput.h"
>>>>
>>>> respectively.
>>>>
>>>> Thanks,
>>>> Laszlo
>>>>
>>>>>
>>>>> -Jordan
>>>>>
>>>>


^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [edk2-devel] [PATCH 02/10] MdePkg/PiFirmwareFile: fix undefined behavior in SECTION_SIZE
  2019-04-16 23:25             ` Andrew Fish
@ 2019-04-17 10:29               ` Laszlo Ersek
  2019-04-17 11:44                 ` Andrew Fish
  0 siblings, 1 reply; 52+ messages in thread
From: Laszlo Ersek @ 2019-04-17 10:29 UTC (permalink / raw)
  To: Andrew Fish, devel, Jordan Justen; +Cc: Mike Kinney, Liming Gao

Hi Andrew,

On 04/17/19 01:25, Andrew Fish wrote:
> 
> 
>> On Apr 16, 2019, at 11:48 AM, Jordan Justen <jordan.l.justen@intel.com> wrote:
>>
>> On 2019-04-16 03:59:48, Laszlo Ersek wrote:
>>> On 04/16/19 11:04, Jordan Justen wrote:
>>>> On 2019-04-15 09:15:31, Laszlo Ersek wrote:
>>>>> On 04/14/19 09:19, Jordan Justen wrote:
>>>>>> On 2019-04-12 16:31:20, Laszlo Ersek wrote:
>>>>>>> RH covscan justifiedly reports that accessing
>>>>>>> "EFI_COMMON_SECTION_HEADER.Size", which is of type UINT8[3], through a
>>>>>>> (UINT32*), is undefined behavior:
>>>>>>>
>>>>>>>> Error: OVERRUN (CWE-119):
>>>>>>>> edk2-89910a39dcfd/OvmfPkg/Sec/SecMain.c:178: overrun-local: Overrunning
>>>>>>>> array of 3 bytes at byte offset 3 by dereferencing pointer
>>>>>>>> "(UINT32 *)((EFI_COMMON_SECTION_HEADER *)(UINTN)Section)->Size".
>>>>>>>> #  176|       Section = (EFI_COMMON_SECTION_HEADER*)(UINTN) CurrentAddress;
>>>>>>>> #  177|
>>>>>>>> #  178|->     Size = SECTION_SIZE (Section);
>>>>>>>> #  179|       if (Size < sizeof (*Section)) {
>>>>>>>> #  180|         return EFI_VOLUME_CORRUPTED;
>>>>>>>
>>>>>>> Fix this by introducing EFI_COMMON_SECTION_HEADER_UNION, and expressing
>>>>>>> SECTION_SIZE() in terms of "EFI_COMMON_SECTION_HEADER_UNION.Uint32".
>>>>>>>
>>>>>>> Cc: Liming Gao <liming.gao@intel.com>
>>>>>>> Cc: Michael D Kinney <michael.d.kinney@intel.com>
>>>>>>> Bugzilla: https://bugzilla.tianocore.org/show_bug.cgi?id=1710
>>>>>>> Issue: scan-1007.txt
>>>>>>> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
>>>>>>> ---
>>>>>>> MdePkg/Include/Pi/PiFirmwareFile.h | 10 +++++++++-
>>>>>>> 1 file changed, 9 insertions(+), 1 deletion(-)
>>>>>>>
>>>>>>> diff --git a/MdePkg/Include/Pi/PiFirmwareFile.h b/MdePkg/Include/Pi/PiFirmwareFile.h
>>>>>>> index a9f3bcc4eb8e..4fce8298d1c0 100644
>>>>>>> --- a/MdePkg/Include/Pi/PiFirmwareFile.h
>>>>>>> +++ b/MdePkg/Include/Pi/PiFirmwareFile.h
>>>>>>> @@ -229,16 +229,24 @@ typedef struct {
>>>>>>>   ///
>>>>>>>   UINT8             Size[3];
>>>>>>>   EFI_SECTION_TYPE  Type;
>>>>>>>   ///
>>>>>>>   /// Declares the section type.
>>>>>>>   ///
>>>>>>> } EFI_COMMON_SECTION_HEADER;
>>>>>>>
>>>>>>> +///
>>>>>>> +/// Union that permits accessing EFI_COMMON_SECTION_HEADER as a UINT32 object.
>>>>>>> +///
>>>>>>> +typedef union {
>>>>>>> +  EFI_COMMON_SECTION_HEADER Hdr;
>>>>>>> +  UINT32                    Uint32;
>>>>>>> +} EFI_COMMON_SECTION_HEADER_UNION;
>>>>>>> +
>>>>>>> typedef struct {
>>>>>>>   ///
>>>>>>>   /// A 24-bit unsigned integer that contains the total size of the section in bytes,
>>>>>>>   /// including the EFI_COMMON_SECTION_HEADER.
>>>>>>>   ///
>>>>>>>   UINT8             Size[3];
>>>>>>>
>>>>>>>   EFI_SECTION_TYPE  Type;
>>>>>>> @@ -476,17 +484,17 @@ typedef struct {
>>>>>>>   /// A UINT16 that represents a particular build. Subsequent builds have monotonically
>>>>>>>   /// increasing build numbers relative to earlier builds.
>>>>>>>   ///
>>>>>>>   UINT16                        BuildNumber;
>>>>>>>   CHAR16                        VersionString[1];
>>>>>>> } EFI_VERSION_SECTION2;
>>>>>>>
>>>>>>> #define SECTION_SIZE(SectionHeaderPtr) \
>>>>>>> -    ((UINT32) (*((UINT32 *) ((EFI_COMMON_SECTION_HEADER *) (UINTN) SectionHeaderPtr)->Size) & 0x00ffffff))
>>>>>>> +    (((EFI_COMMON_SECTION_HEADER_UNION *) (UINTN) (SectionHeaderPtr))->Uint32 & 0x00ffffff)
>>>>>>
>>>>>> Mike, all,
>>>>>>
>>>>>> Can we add a typedef for EFI_COMMON_SECTION_HEADER_UNION if it's not
>>>>>> in the PI spec?
>>>>>>
>>>>>> If it's not allowed, I think something like this might work too:
>>>>>>
>>>>>> #define SECTION_SIZE(SectionHeaderPtr) \
>>>>>>    (*((UINT32*)(UINTN)(SectionHeaderPtr)) & 0x00ffffff)
>>>>>
>>>>> (Less importantly:)
>>>>>
>>>>> It might shut up the static analyzer, but regarding the C standard, it's
>>>>> equally undefined behavior.
>>>>
>>>> I think you are still accessing it through a UINT32*, since you are
>>>> using a pointer to a union, and an field of type UINT32 within the
>>>> union.
>>>
>>> Using a union makes the behavior well-defined.
>>>
>>>> 6.2.7 Compatible type and composite type
>>>>
>>>> 1 Two types have compatible type if their types are the same.
>>>>  Additional rules for determining whether two types are compatible
>>>>  are described in [...]
>>>
>>>> 6.5 Expressions
>>>>
>>>> 6 The /effective type/ of an object for an access to its stored value
>>>>  is the declared type of the object, if any. [...]
>>>>
>>>> 7 An object shall have its stored value accessed only by an lvalue
>>>>  expression that has one of the following types:
>>
>> I think maybe this all applies to lvalues, not rvalues. The boon and
>> bane of C is that any pointer can be easily cast to a pointer of any
>> other type and then dereferenced.
>>
>> If the pointer is dereferenced to a type that is larger, then I
>> understand that there are cases where deferencing the pointer could
>> have unintended side effects, but that is not the case here.
>>
>> The dereference could also be undefined if big-endian was in the
>> picture, but UEFI restricts that.
>>
>> Of course none of this stops a tool from trying to delve further into
>> the pointer usage to look for possible issues.
>>
>> But, I don't see how any of this changes the fact that with or without
>> the union, we are dereferencing a UINT32 pointer.
>>
> 
> The thing that is really saving us is the 4 byte alignment requirement for FV sections in the PI Spec, but that is not expressed by EFI_COMMON_SECTION_HEADER to the compiler. The union is better as it enforces alignment of the structure. This enforced alignment is likely what makes static analysis tools happy. 
> 
> I don't think the casting in the existing SECTION_SIZE is UB (Undefined Behavior) as the extraction is not the issue as you are telling the compiler to extract 4 unaligned bytes. That is the same as accessing a packed structure. But this is only because you started with a byte pointer so you are not really violating any C alignment rules. Thus in a case like our cast, or pragma pack(1),  the compiler has extra alignment info provided so all is good, the issue is if you assign a pointer into the type the only alignment info the compiler has is the rules for that type, and non of packing rules. A lot of the above C rules are making it clear what the compiler does in these cases. 
> 
> Ironically the new union macro is undefined behavior at runtime during the cast if the section header is not 4 byte algined since you did not start with something (unsigned char pointer) that allowed byte access. See my example of the ubsan fault. 
> 
> The nice thing about the union is it tells the compiler our intended constraint from the PI spec. 
> 
> // This 5 byte structure will align EFI_COMMON_SECTION_HEADER on an odd byte boundary. 
> typedef struct {
>   UINT8                     Count;
>   EFI_COMMON_SECTION_HEADER Sec;
> } UNALIGNED_SECTION_HEADER;
> 
> // This will properly align EFI_COMMON_SECTION_HEADER_UNION on a 4 byte boundary. 
> typedef struct {
>   UINT8                           Count;
>   EFI_COMMON_SECTION_HEADER_UNION Sec;
> } ALIGNED_SECTION_HEADER2;
> 
> I tried to validate this with the clang ubsan... The only runtime UB was the new macro against UNALIGNED_SECTION_HEADER. ALIGNED_SECTION_HEADER2 with the new union aligned everything correctly and works fine. 
> 
> ./a.out
> Fv.c:55:11: runtime error: member access within misaligned address 0x000104b23021 for type 'EFI_COMMON_SECTION_HEADER_UNION', which requires 4 byte alignment
> 0x000104b23021: note: pointer points here
>  00 00 00  ff 01 02 03 10 00 00 00  aa 00 00 00 01 02 03 10  2a 2f b2 04 01 00 00 00  34 00 00 00 0d
>               ^ 
> Fv.c:55:11: runtime error: load of misaligned address 0x000104b23021 for type 'UINT32' (aka 'unsigned int'), which requires 4 byte alignment
> 0x000104b23021: note: pointer points here
>  00 00 00  ff 01 02 03 10 00 00 00  aa 00 00 00 01 02 03 10  2a 2f b2 04 01 00 00 00  34 00 00 00 0d
>               ^ 
> 
> $ clang -fsanitize=undefined Fv.c
> $ cat Fv.c
> typedef unsigned char       UINT8;
> typedef UINT8               EFI_SECTION_TYPE;
> typedef unsigned int        UINT32;
> typedef unsigned long long  UINTN;
> 
> typedef UINT8 EFI_SECTION_TYPE;
> 
> ///
> /// Common section header.
> /// 
> typedef struct {
>   ///
>   /// A 24-bit unsigned integer that contains the total size of the section in bytes, 
>   /// including the EFI_COMMON_SECTION_HEADER.
>   ///
>   UINT8             Size[3];
>   EFI_SECTION_TYPE  Type;
>   ///
>   /// Declares the section type.
>   ///
> } EFI_COMMON_SECTION_HEADER;
> 
> typedef union {
>   EFI_COMMON_SECTION_HEADER Hdr;
>   UINT32                    Uint32;
> } EFI_COMMON_SECTION_HEADER_UNION;
> 
> 
> #define SECTION_SIZE(SectionHeaderPtr) \
>     ((UINT32) (*((UINT32 *) ((EFI_COMMON_SECTION_HEADER *) (UINTN) SectionHeaderPtr)->Size) & 0x00ffffff))
> 
> #define SECTION_SIZE2(SectionHeaderPtr) \
>     (((EFI_COMMON_SECTION_HEADER_UNION *) (UINTN) (SectionHeaderPtr))->Uint32 & 0x00ffffff)
> 
> 
> typedef struct {
>   UINT8                     Count;
>   EFI_COMMON_SECTION_HEADER Sec;
> } UNALIGNED_SECTION_HEADER;
> 
> typedef struct {
>   UINT8                           Count;
>   EFI_COMMON_SECTION_HEADER_UNION Sec;
> } ALIGNED_SECTION_HEADER2;
> 
> UNALIGNED_SECTION_HEADER  gSection  = { 0xff, { { 0x01, 0x02, 0x3 }, 0x10 } };
> ALIGNED_SECTION_HEADER2   gSection2 = { 0xaa, {   } };
> int
> main (int argc, char **argv)
> {
>   UINT32 Size, Size2;
>   gSection2.Sec.Uint32 = 0x10030201;
>   
>   Size  = SECTION_SIZE(&gSection.Sec);
>   Size2 = SECTION_SIZE2(&gSection.Sec);  // runtime error:
> 
>   Size  = SECTION_SIZE(&gSection2.Sec);
>   Size2 = SECTION_SIZE2(&gSection2.Sec);
>   return Size == Size2;
> }

Thank you for this investigation! I really appreciate that you wrote it
up, and the example code makes your point clear.

If my understanding is correct, you are saying that, from an alignment
perspective, both the pre-patch code and the post-patch code are
correct. In other words, we might want to apply the patch, but there
isn't a strong necessity for it. Is my understanding correct?

If so, I'd like to point out that the original warning (see the commit
message) wasn't about alignment, but about "overrun":

-------
Error: OVERRUN (CWE-119):
edk2-89910a39dcfd/OvmfPkg/Sec/SecMain.c:178: overrun-local: Overrunning
array of 3 bytes at byte offset 3 by dereferencing pointer
"(UINT32 *)((EFI_COMMON_SECTION_HEADER *)(UINTN)Section)->Size"
-------

This warning was reported by "RH covscan" as "CPPCHECK_WARNING"; that
is, it comes from the cppcheck tool, not from clang-analyzer. So while I
agree that the pre-patch code may not imply an invalid alignment for the
compiler, I claim that the *overrun* (i.e., a different issue) does exist:

- The pre-patch code takes the Size member, which is an array of 3 UINT8
elements,
- in that context, the Size member is implicitly converted to a pointer
to the first UINT8 element of the array, i.e. &Size[0],
- the resultant pointer is explicitly cast to a (UINT32*), and then
dereferenced.

And the last step violates the effective type rules that I quoted
up-thread, because UINT32 is not a type that is compatible with UINT8.

> PS If folks disagree I know a person that owns the clang ubsan architecture and sits on the C/C++ standards committees. I had a long talk with this person recently about C alignment UB and I think I understand it a little better from the compiler point of view now. 

I certainly accept (and thank you for) your explanation of the
alignment. The patch intends to fix an issue that is not
alignment-related though.

Thanks!
Laszlo

> 
>> -Jordan
>>
>>>>
>>>>  \u2014 a type compatible with the effective type of the object,
>>>>  \u2014 a qualified version of a type compatible with the effective type
>>>>    of the object,
>>>>  \u2014 a type that is the signed or unsigned type corresponding to the
>>>>    effective type of the object,
>>>>  \u2014 a type that is the signed or unsigned type corresponding to a
>>>>    qualified version of the effective type of the object,
>>>>  \u2014 an aggregate or union type that includes one of the aforementioned
>>>>    types among its members (including, recursively, a member of a
>>>>    subaggregate or contained union), or
>>>>  \u2014 a character type.
>>>
>>> - Regarding 6.5p6, the original object we intend to access has
>>> (declared) type EFI_COMMON_SECTION_HEADER. Therefore the effective type
>>> is EFI_COMMON_SECTION_HEADER.
>>>
>>> - Based on 6.2.7p1, EFI_COMMON_SECTION_HEADER is compatible with
>>> EFI_COMMON_SECTION_HEADER. (Because they are the same.)
>>>
>>> - Based on 6.5p7 item #5, EFI_COMMON_SECTION_HEADER can be accessed as
>>> EFI_COMMON_SECTION_HEADER_UNION, because EFI_COMMON_SECTION_HEADER_UNION
>>> includes "a type compatible with the effective type of the object" (#1)
>>> among its members -- namely an EFI_COMMON_SECTION_HEADER, which is
>>> compatible with EFI_COMMON_SECTION_HEADER, because they are the same.
>>>
>>>> I guess it might more well defined to shift the bytes, like is
>>>> sometimes done with the FFS file sizes.
>>>
>>> I did that (i.e. byte-shifting) in the other patch:
>>>
>>>  [edk2-devel] [PATCH 04/10]
>>>  MdePkg/PiFirmwareFile: fix undefined behavior in FFS_FILE_SIZE
>>>
>>> but for SECTION_SIZE, the union is well-defined too.
>>>
>>> Thanks,
>>> Laszlo
>>>
>>>>
>>>> -Jordan
>>>>
>>>>> Anyway I don't feel too strongly about this, given that we disable the
>>>>> strict aliasing / effective type rules in "tools_def.template"
>>>>> ("-fno-strict-aliasing").
>>>>>
>>>>>> Then again, I see SECTION_SIZE is not in the spec, so maybe it's ok to
>>>>>> add the typedef.
>>>>>
>>>>> (More importantly:)
>>>>>
>>>>> Indeed the doubt you voice about ..._UNION crossed my mind, but then I
>>>>> too searched the PI spec for SECTION_SIZE, with no hits.
>>>>>
>>>>> Beyond that, I searched both the PI and UEFI specs, for "_UNION" --
>>>>> again no hits, despite our definitions of:
>>>>>
>>>>> - EFI_IMAGE_OPTIONAL_HEADER_UNION
>>>>> - EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION
>>>>>
>>>>> in
>>>>>
>>>>> - "MdePkg/Include/IndustryStandard/PeImage.h"
>>>>> - "MdePkg/Include/Protocol/GraphicsOutput.h"
>>>>>
>>>>> respectively.
>>>>>
>>>>> Thanks,
>>>>> Laszlo
>>>>>
>>>>>>
>>>>>> -Jordan
>>>>>>
>>>>>
>>>
>>
>> 
>>
> 
> 


^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [edk2-devel] [PATCH 02/10] MdePkg/PiFirmwareFile: fix undefined behavior in SECTION_SIZE
  2019-04-17 10:29               ` Laszlo Ersek
@ 2019-04-17 11:44                 ` Andrew Fish
  2019-04-17 14:59                   ` Laszlo Ersek
  0 siblings, 1 reply; 52+ messages in thread
From: Andrew Fish @ 2019-04-17 11:44 UTC (permalink / raw)
  To: Laszlo Ersek; +Cc: devel, Jordan Justen, Mike Kinney, Liming Gao

[-- Attachment #1: Type: text/plain, Size: 16160 bytes --]



> On Apr 17, 2019, at 3:29 AM, Laszlo Ersek <lersek@redhat.com> wrote:
> 
> Hi Andrew,
> 
> On 04/17/19 01:25, Andrew Fish wrote:
>> 
>> 
>>> On Apr 16, 2019, at 11:48 AM, Jordan Justen <jordan.l.justen@intel.com> wrote:
>>> 
>>> On 2019-04-16 03:59:48, Laszlo Ersek wrote:
>>>> On 04/16/19 11:04, Jordan Justen wrote:
>>>>> On 2019-04-15 09:15:31, Laszlo Ersek wrote:
>>>>>> On 04/14/19 09:19, Jordan Justen wrote:
>>>>>>> On 2019-04-12 16:31:20, Laszlo Ersek wrote:
>>>>>>>> RH covscan justifiedly reports that accessing
>>>>>>>> "EFI_COMMON_SECTION_HEADER.Size", which is of type UINT8[3], through a
>>>>>>>> (UINT32*), is undefined behavior:
>>>>>>>> 
>>>>>>>>> Error: OVERRUN (CWE-119):
>>>>>>>>> edk2-89910a39dcfd/OvmfPkg/Sec/SecMain.c:178: overrun-local: Overrunning
>>>>>>>>> array of 3 bytes at byte offset 3 by dereferencing pointer
>>>>>>>>> "(UINT32 *)((EFI_COMMON_SECTION_HEADER *)(UINTN)Section)->Size".
>>>>>>>>> #  176|       Section = (EFI_COMMON_SECTION_HEADER*)(UINTN) CurrentAddress;
>>>>>>>>> #  177|
>>>>>>>>> #  178|->     Size = SECTION_SIZE (Section);
>>>>>>>>> #  179|       if (Size < sizeof (*Section)) {
>>>>>>>>> #  180|         return EFI_VOLUME_CORRUPTED;
>>>>>>>> 
>>>>>>>> Fix this by introducing EFI_COMMON_SECTION_HEADER_UNION, and expressing
>>>>>>>> SECTION_SIZE() in terms of "EFI_COMMON_SECTION_HEADER_UNION.Uint32".
>>>>>>>> 
>>>>>>>> Cc: Liming Gao <liming.gao@intel.com>
>>>>>>>> Cc: Michael D Kinney <michael.d.kinney@intel.com>
>>>>>>>> Bugzilla: https://bugzilla.tianocore.org/show_bug.cgi?id=1710
>>>>>>>> Issue: scan-1007.txt
>>>>>>>> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
>>>>>>>> ---
>>>>>>>> MdePkg/Include/Pi/PiFirmwareFile.h | 10 +++++++++-
>>>>>>>> 1 file changed, 9 insertions(+), 1 deletion(-)
>>>>>>>> 
>>>>>>>> diff --git a/MdePkg/Include/Pi/PiFirmwareFile.h b/MdePkg/Include/Pi/PiFirmwareFile.h
>>>>>>>> index a9f3bcc4eb8e..4fce8298d1c0 100644
>>>>>>>> --- a/MdePkg/Include/Pi/PiFirmwareFile.h
>>>>>>>> +++ b/MdePkg/Include/Pi/PiFirmwareFile.h
>>>>>>>> @@ -229,16 +229,24 @@ typedef struct {
>>>>>>>>  ///
>>>>>>>>  UINT8             Size[3];
>>>>>>>>  EFI_SECTION_TYPE  Type;
>>>>>>>>  ///
>>>>>>>>  /// Declares the section type.
>>>>>>>>  ///
>>>>>>>> } EFI_COMMON_SECTION_HEADER;
>>>>>>>> 
>>>>>>>> +///
>>>>>>>> +/// Union that permits accessing EFI_COMMON_SECTION_HEADER as a UINT32 object.
>>>>>>>> +///
>>>>>>>> +typedef union {
>>>>>>>> +  EFI_COMMON_SECTION_HEADER Hdr;
>>>>>>>> +  UINT32                    Uint32;
>>>>>>>> +} EFI_COMMON_SECTION_HEADER_UNION;
>>>>>>>> +
>>>>>>>> typedef struct {
>>>>>>>>  ///
>>>>>>>>  /// A 24-bit unsigned integer that contains the total size of the section in bytes,
>>>>>>>>  /// including the EFI_COMMON_SECTION_HEADER.
>>>>>>>>  ///
>>>>>>>>  UINT8             Size[3];
>>>>>>>> 
>>>>>>>>  EFI_SECTION_TYPE  Type;
>>>>>>>> @@ -476,17 +484,17 @@ typedef struct {
>>>>>>>>  /// A UINT16 that represents a particular build. Subsequent builds have monotonically
>>>>>>>>  /// increasing build numbers relative to earlier builds.
>>>>>>>>  ///
>>>>>>>>  UINT16                        BuildNumber;
>>>>>>>>  CHAR16                        VersionString[1];
>>>>>>>> } EFI_VERSION_SECTION2;
>>>>>>>> 
>>>>>>>> #define SECTION_SIZE(SectionHeaderPtr) \
>>>>>>>> -    ((UINT32) (*((UINT32 *) ((EFI_COMMON_SECTION_HEADER *) (UINTN) SectionHeaderPtr)->Size) & 0x00ffffff))
>>>>>>>> +    (((EFI_COMMON_SECTION_HEADER_UNION *) (UINTN) (SectionHeaderPtr))->Uint32 & 0x00ffffff)
>>>>>>> 
>>>>>>> Mike, all,
>>>>>>> 
>>>>>>> Can we add a typedef for EFI_COMMON_SECTION_HEADER_UNION if it's not
>>>>>>> in the PI spec?
>>>>>>> 
>>>>>>> If it's not allowed, I think something like this might work too:
>>>>>>> 
>>>>>>> #define SECTION_SIZE(SectionHeaderPtr) \
>>>>>>>   (*((UINT32*)(UINTN)(SectionHeaderPtr)) & 0x00ffffff)
>>>>>> 
>>>>>> (Less importantly:)
>>>>>> 
>>>>>> It might shut up the static analyzer, but regarding the C standard, it's
>>>>>> equally undefined behavior.
>>>>> 
>>>>> I think you are still accessing it through a UINT32*, since you are
>>>>> using a pointer to a union, and an field of type UINT32 within the
>>>>> union.
>>>> 
>>>> Using a union makes the behavior well-defined.
>>>> 
>>>>> 6.2.7 Compatible type and composite type
>>>>> 
>>>>> 1 Two types have compatible type if their types are the same.
>>>>> Additional rules for determining whether two types are compatible
>>>>> are described in [...]
>>>> 
>>>>> 6.5 Expressions
>>>>> 
>>>>> 6 The /effective type/ of an object for an access to its stored value
>>>>> is the declared type of the object, if any. [...]
>>>>> 
>>>>> 7 An object shall have its stored value accessed only by an lvalue
>>>>> expression that has one of the following types:
>>> 
>>> I think maybe this all applies to lvalues, not rvalues. The boon and
>>> bane of C is that any pointer can be easily cast to a pointer of any
>>> other type and then dereferenced.
>>> 
>>> If the pointer is dereferenced to a type that is larger, then I
>>> understand that there are cases where deferencing the pointer could
>>> have unintended side effects, but that is not the case here.
>>> 
>>> The dereference could also be undefined if big-endian was in the
>>> picture, but UEFI restricts that.
>>> 
>>> Of course none of this stops a tool from trying to delve further into
>>> the pointer usage to look for possible issues.
>>> 
>>> But, I don't see how any of this changes the fact that with or without
>>> the union, we are dereferencing a UINT32 pointer.
>>> 
>> 
>> The thing that is really saving us is the 4 byte alignment requirement for FV sections in the PI Spec, but that is not expressed by EFI_COMMON_SECTION_HEADER to the compiler. The union is better as it enforces alignment of the structure. This enforced alignment is likely what makes static analysis tools happy. 
>> 
>> I don't think the casting in the existing SECTION_SIZE is UB (Undefined Behavior) as the extraction is not the issue as you are telling the compiler to extract 4 unaligned bytes. That is the same as accessing a packed structure. But this is only because you started with a byte pointer so you are not really violating any C alignment rules. Thus in a case like our cast, or pragma pack(1),  the compiler has extra alignment info provided so all is good, the issue is if you assign a pointer into the type the only alignment info the compiler has is the rules for that type, and non of packing rules. A lot of the above C rules are making it clear what the compiler does in these cases. 
>> 
>> Ironically the new union macro is undefined behavior at runtime during the cast if the section header is not 4 byte algined since you did not start with something (unsigned char pointer) that allowed byte access. See my example of the ubsan fault. 
>> 
>> The nice thing about the union is it tells the compiler our intended constraint from the PI spec. 
>> 
>> // This 5 byte structure will align EFI_COMMON_SECTION_HEADER on an odd byte boundary. 
>> typedef struct {
>>  UINT8                     Count;
>>  EFI_COMMON_SECTION_HEADER Sec;
>> } UNALIGNED_SECTION_HEADER;
>> 
>> // This will properly align EFI_COMMON_SECTION_HEADER_UNION on a 4 byte boundary. 
>> typedef struct {
>>  UINT8                           Count;
>>  EFI_COMMON_SECTION_HEADER_UNION Sec;
>> } ALIGNED_SECTION_HEADER2;
>> 
>> I tried to validate this with the clang ubsan... The only runtime UB was the new macro against UNALIGNED_SECTION_HEADER. ALIGNED_SECTION_HEADER2 with the new union aligned everything correctly and works fine. 
>> 
>> ./a.out
>> Fv.c:55:11: runtime error: member access within misaligned address 0x000104b23021 for type 'EFI_COMMON_SECTION_HEADER_UNION', which requires 4 byte alignment
>> 0x000104b23021: note: pointer points here
>> 00 00 00  ff 01 02 03 10 00 00 00  aa 00 00 00 01 02 03 10  2a 2f b2 04 01 00 00 00  34 00 00 00 0d
>>              ^ 
>> Fv.c:55:11: runtime error: load of misaligned address 0x000104b23021 for type 'UINT32' (aka 'unsigned int'), which requires 4 byte alignment
>> 0x000104b23021: note: pointer points here
>> 00 00 00  ff 01 02 03 10 00 00 00  aa 00 00 00 01 02 03 10  2a 2f b2 04 01 00 00 00  34 00 00 00 0d
>>              ^ 
>> 
>> $ clang -fsanitize=undefined Fv.c
>> $ cat Fv.c
>> typedef unsigned char       UINT8;
>> typedef UINT8               EFI_SECTION_TYPE;
>> typedef unsigned int        UINT32;
>> typedef unsigned long long  UINTN;
>> 
>> typedef UINT8 EFI_SECTION_TYPE;
>> 
>> ///
>> /// Common section header.
>> /// 
>> typedef struct {
>>  ///
>>  /// A 24-bit unsigned integer that contains the total size of the section in bytes, 
>>  /// including the EFI_COMMON_SECTION_HEADER.
>>  ///
>>  UINT8             Size[3];
>>  EFI_SECTION_TYPE  Type;
>>  ///
>>  /// Declares the section type.
>>  ///
>> } EFI_COMMON_SECTION_HEADER;
>> 
>> typedef union {
>>  EFI_COMMON_SECTION_HEADER Hdr;
>>  UINT32                    Uint32;
>> } EFI_COMMON_SECTION_HEADER_UNION;
>> 
>> 
>> #define SECTION_SIZE(SectionHeaderPtr) \
>>    ((UINT32) (*((UINT32 *) ((EFI_COMMON_SECTION_HEADER *) (UINTN) SectionHeaderPtr)->Size) & 0x00ffffff))
>> 
>> #define SECTION_SIZE2(SectionHeaderPtr) \
>>    (((EFI_COMMON_SECTION_HEADER_UNION *) (UINTN) (SectionHeaderPtr))->Uint32 & 0x00ffffff)
>> 
>> 
>> typedef struct {
>>  UINT8                     Count;
>>  EFI_COMMON_SECTION_HEADER Sec;
>> } UNALIGNED_SECTION_HEADER;
>> 
>> typedef struct {
>>  UINT8                           Count;
>>  EFI_COMMON_SECTION_HEADER_UNION Sec;
>> } ALIGNED_SECTION_HEADER2;
>> 
>> UNALIGNED_SECTION_HEADER  gSection  = { 0xff, { { 0x01, 0x02, 0x3 }, 0x10 } };
>> ALIGNED_SECTION_HEADER2   gSection2 = { 0xaa, {   } };
>> int
>> main (int argc, char **argv)
>> {
>>  UINT32 Size, Size2;
>>  gSection2.Sec.Uint32 = 0x10030201;
>> 
>>  Size  = SECTION_SIZE(&gSection.Sec);
>>  Size2 = SECTION_SIZE2(&gSection.Sec);  // runtime error:
>> 
>>  Size  = SECTION_SIZE(&gSection2.Sec);
>>  Size2 = SECTION_SIZE2(&gSection2.Sec);
>>  return Size == Size2;
>> }
> 
> Thank you for this investigation! I really appreciate that you wrote it
> up, and the example code makes your point clear.
> 
> If my understanding is correct, you are saying that, from an alignment
> perspective, both the pre-patch code and the post-patch code are
> correct. In other words, we might want to apply the patch, but there
> isn't a strong necessity for it. Is my understanding correct?
> 
> If so, I'd like to point out that the original warning (see the commit
> message) wasn't about alignment, but about "overrun":
> 
> -------
> Error: OVERRUN (CWE-119):
> edk2-89910a39dcfd/OvmfPkg/Sec/SecMain.c:178: overrun-local: Overrunning
> array of 3 bytes at byte offset 3 by dereferencing pointer
> "(UINT32 *)((EFI_COMMON_SECTION_HEADER *)(UINTN)Section)->Size"
> -------
> 
> This warning was reported by "RH covscan" as "CPPCHECK_WARNING"; that
> is, it comes from the cppcheck tool, not from clang-analyzer. So while I
> agree that the pre-patch code may not imply an invalid alignment for the
> compiler, I claim that the *overrun* (i.e., a different issue) does exist:
> 
> - The pre-patch code takes the Size member, which is an array of 3 UINT8
> elements,
> - in that context, the Size member is implicitly converted to a pointer
> to the first UINT8 element of the array, i.e. &Size[0],
> - the resultant pointer is explicitly cast to a (UINT32*), and then
> dereferenced.
> 
> And the last step violates the effective type rules that I quoted
> up-thread, because UINT32 is not a type that is compatible with UINT8.
> 
>> PS If folks disagree I know a person that owns the clang ubsan architecture and sits on the C/C++ standards committees. I had a long talk with this person recently about C alignment UB and I think I understand it a little better from the compiler point of view now. 
> 
> I certainly accept (and thank you for) your explanation of the
> alignment. The patch intends to fix an issue that is not
> alignment-related though.
> 

Laszlo,

Sorry I digressed into the C specification discussion, and did not deal with the patch in general. My point is the original code is legal C code. If you lookup CWE-119 it is written as a restriction on what the C language allows. 

As I mentioned casting to specific alignment is legal, as is defining a structure that is pragma pack(1) that can make a UINT32 not be 4 byte aligned. Thus the cast created a legal UINT32 value. A cast to *(UINT32 *) is different that a cast to (UINT32 *). The rules you quote a triggered by the = and not the cast. 

Thus this is undefined behavior in C:
  UINT32 *Ub = (UINT32 *)gSection.Sec.Size;
  Size = *Ub & 0x00ffffff;

And this is not Undefined behavior:
  UINT32 NotUb = *(UINT32 *)gSection.Sec.Size & 0x00ffffff;

I also had a hard time interpreting what C spec was saying, but talking to the people who write the compiler and ubsan cleared it up for me. It also makes sense when you think about it. If you tell the compiler *(UINT32 *) it can know to generate byte reads if the hardware requires aligned access. If you do a (UINT32 *) that new pointer no longer carries the information about the alignment requirement. Thus the  *(UINT32 *) cast is like making a packed structure. 

I agree the union is a good solution to CWE-119 and it better matches the alignment requirement in the PI spec. 

Thanks,

Andrew Fish


> Thanks!
> Laszlo
> 
>> 
>>> -Jordan
>>> 
>>>>> 
>>>>> \u2014 a type compatible with the effective type of the object,
>>>>> \u2014 a qualified version of a type compatible with the effective type
>>>>>   of the object,
>>>>> \u2014 a type that is the signed or unsigned type corresponding to the
>>>>>   effective type of the object,
>>>>> \u2014 a type that is the signed or unsigned type corresponding to a
>>>>>   qualified version of the effective type of the object,
>>>>> \u2014 an aggregate or union type that includes one of the aforementioned
>>>>>   types among its members (including, recursively, a member of a
>>>>>   subaggregate or contained union), or
>>>>> \u2014 a character type.
>>>> 
>>>> - Regarding 6.5p6, the original object we intend to access has
>>>> (declared) type EFI_COMMON_SECTION_HEADER. Therefore the effective type
>>>> is EFI_COMMON_SECTION_HEADER.
>>>> 
>>>> - Based on 6.2.7p1, EFI_COMMON_SECTION_HEADER is compatible with
>>>> EFI_COMMON_SECTION_HEADER. (Because they are the same.)
>>>> 
>>>> - Based on 6.5p7 item #5, EFI_COMMON_SECTION_HEADER can be accessed as
>>>> EFI_COMMON_SECTION_HEADER_UNION, because EFI_COMMON_SECTION_HEADER_UNION
>>>> includes "a type compatible with the effective type of the object" (#1)
>>>> among its members -- namely an EFI_COMMON_SECTION_HEADER, which is
>>>> compatible with EFI_COMMON_SECTION_HEADER, because they are the same.
>>>> 
>>>>> I guess it might more well defined to shift the bytes, like is
>>>>> sometimes done with the FFS file sizes.
>>>> 
>>>> I did that (i.e. byte-shifting) in the other patch:
>>>> 
>>>> [edk2-devel] [PATCH 04/10]
>>>> MdePkg/PiFirmwareFile: fix undefined behavior in FFS_FILE_SIZE
>>>> 
>>>> but for SECTION_SIZE, the union is well-defined too.
>>>> 
>>>> Thanks,
>>>> Laszlo
>>>> 
>>>>> 
>>>>> -Jordan
>>>>> 
>>>>>> Anyway I don't feel too strongly about this, given that we disable the
>>>>>> strict aliasing / effective type rules in "tools_def.template"
>>>>>> ("-fno-strict-aliasing").
>>>>>> 
>>>>>>> Then again, I see SECTION_SIZE is not in the spec, so maybe it's ok to
>>>>>>> add the typedef.
>>>>>> 
>>>>>> (More importantly:)
>>>>>> 
>>>>>> Indeed the doubt you voice about ..._UNION crossed my mind, but then I
>>>>>> too searched the PI spec for SECTION_SIZE, with no hits.
>>>>>> 
>>>>>> Beyond that, I searched both the PI and UEFI specs, for "_UNION" --
>>>>>> again no hits, despite our definitions of:
>>>>>> 
>>>>>> - EFI_IMAGE_OPTIONAL_HEADER_UNION
>>>>>> - EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION
>>>>>> 
>>>>>> in
>>>>>> 
>>>>>> - "MdePkg/Include/IndustryStandard/PeImage.h"
>>>>>> - "MdePkg/Include/Protocol/GraphicsOutput.h"
>>>>>> 
>>>>>> respectively.
>>>>>> 
>>>>>> Thanks,
>>>>>> Laszlo
>>>>>> 
>>>>>>> 
>>>>>>> -Jordan
>>>>>>> 
>>>>>> 
>>>> 
>>> 
>>> 


[-- Attachment #2: Type: text/html, Size: 51325 bytes --]

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [edk2-devel] [PATCH 02/10] MdePkg/PiFirmwareFile: fix undefined behavior in SECTION_SIZE
  2019-04-17 11:44                 ` Andrew Fish
@ 2019-04-17 14:59                   ` Laszlo Ersek
  2019-04-17 19:35                     ` Jordan Justen
  0 siblings, 1 reply; 52+ messages in thread
From: Laszlo Ersek @ 2019-04-17 14:59 UTC (permalink / raw)
  To: Andrew Fish; +Cc: devel, Jordan Justen, Mike Kinney, Liming Gao

On 04/17/19 13:44, Andrew Fish wrote:

> Sorry I digressed into the C specification discussion, and did not
> deal with the patch in general. My point is the original code is legal
> C code. If you lookup CWE-119 it is written as a restriction on what
> the C language allows.
>
> As I mentioned casting to specific alignment is legal, as is defining
> a structure that is pragma pack(1) that can make a UINT32 not be 4
> byte aligned. Thus the cast created a legal UINT32 value. A cast to
> *(UINT32 *) is different that a cast to (UINT32 *). The rules you
> quote a triggered by the = and not the cast.
>
> Thus this is undefined behavior in C:
>   UINT32 *Ub = (UINT32 *)gSection.Sec.Size;
>   Size = *Ub & 0x00ffffff;
>
> And this is not Undefined behavior:
>   UINT32 NotUb = *(UINT32 *)gSection.Sec.Size & 0x00ffffff;

I agree the 2nd snippet may not be UB due to alignment violations
*alone*.

It is still UB due to violating the effective type rules.

> I also had a hard time interpreting what C spec was saying, but
> talking to the people who write the compiler and ubsan cleared it up
> for me. It also makes sense when you think about it. If you tell the
> compiler *(UINT32 *) it can know to generate byte reads if the
> hardware requires aligned access. If you do a (UINT32 *) that new
> pointer no longer carries the information about the alignment
> requirement. Thus the  *(UINT32 *) cast is like making a packed
> structure.

Yes, I think I'm clear on how the alignment information is carried
around, and when it is lost. In your first example above, due to us
forming a separate (standalone) pointer, we lose the alignment
information, and then the assignment is undefined due to an alignment
violation. While in the second example, the alignment information is not
lost, and the assignment is not undefined on an alignment basis *alone*.

However: the second assignment is *still* undefined, because it violates
the effective type rules. Here's a more direct example for the same:

STATIC UINT64 mUint64;

int main(void)
{
  UINT16 *Uint16Ptr;

  Uint16Ptr = (UINT16 *)&mUint64;
  *Uint16Ptr = 1;
  return 0;
}

The assignment to (*Uint16Ptr) is fine from the alignment perspective,
but it is nevertheless undefined, because it breaks the effective type
rules. Namely, UINT16 (the type used for the access) is not compatible
with UINT64 (the effective type of mUint64).

Normally, we don't care about this situation in edk2 -- in fact we write
loads of code like the above --, but we get away with that only because
we force the toolchains to ignore the effective type rules. For GCC in
particular, the option is "-fno-strict-aliasing".

The only reason I've posted this patch is that "cppcheck" (invoked as a
part of "RH covscan") doesn't care about "-fno-strict-aliasing". And
while "cppcheck" happens to report the overrun, and not the type
punning, the way to remove the warning is to adhere to all the C rules
in the expression, even though we have "-fno-strict-aliasing" in place.

> I agree the union is a good solution to CWE-119 and it better matches
> the alignment requirement in the PI spec.

Thank you.

I'll wait a bit longer to see if Jordan accepts this 02/10 patch based
on the most recent comments, and whether Liming or Mike accepts 04/10.

If Jordan remains unconvinced on SECTION_SIZE (in this 02/10 patch), and
Liming or Mike are fine with 04/10, I can rework 02/10 to follow 04/10.

If Jordan remains unconvinced but Mike or Liming prefers the union, then
we have a stalemate and I'll abandon the patch set.

Thanks,
Laszlo

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [edk2-devel] [PATCH 04/10] MdePkg/PiFirmwareFile: fix undefined behavior in FFS_FILE_SIZE
  2019-04-12 23:31 ` [PATCH 04/10] MdePkg/PiFirmwareFile: fix undefined behavior in FFS_FILE_SIZE Laszlo Ersek
  2019-04-15 17:23   ` [edk2-devel] " Philippe Mathieu-Daudé
@ 2019-04-17 17:52   ` Michael D Kinney
  2019-04-17 18:31     ` Michael D Kinney
                       ` (2 more replies)
  1 sibling, 3 replies; 52+ messages in thread
From: Michael D Kinney @ 2019-04-17 17:52 UTC (permalink / raw)
  To: devel@edk2.groups.io, lersek@redhat.com, Kinney, Michael D; +Cc: Gao, Liming

Laszlo,

I have been following this thread.  I think the style
used here to access the 3 array elements to build the
24-bit size value is the best approach.  I prefer this
over adding the union.

I agree there is a read overrun issue when using UINT32 to
read the Size[3] array contents.

I do not think this is a real issue in practice, because the
Size[3] array accessed is part of the larger
EFI_COMMON_SECTION_HEADER structure.  However, we always should
clean up code to not do any read/write overruns without this
type of analysis and the need to keep track of exceptions.

There is a related set of code in the BaseLib for Read/Write
Unaligned24().

UINT32
EFIAPI
ReadUnaligned24 (
  IN CONST UINT32              *Buffer
  );

UINT32
EFIAPI
WriteUnaligned24 (
  OUT UINT32                    *Buffer,
  IN  UINT32                    Value
  );

This API does not get flagged for read overrun issues because
a UINT32 is passed in.  However, for CPU archs that required aligned
access, the 24-bit value must be read in pieces.  This is why there
are 2 different implementations:

IA32/X64
========
UINT32
EFIAPI
ReadUnaligned24 (
  IN CONST UINT32              *Buffer
  )
{
  ASSERT (Buffer != NULL);

  return *Buffer & 0xffffff;
}


ARM/AARCH64
============
UINT32
EFIAPI
ReadUnaligned24 (
  IN CONST UINT32              *Buffer
  )
{
  ASSERT (Buffer != NULL);

  return (UINT32)(
            ReadUnaligned16 ((UINT16*)Buffer) |
            (((UINT8*)Buffer)[2] << 16)
            );
}

The ARM/ARCH64 implementation is clean because it does
not do a read overrun of the 24-bit field.  The IA32/X64
implementation may have an issue because it reads a 32-bit
value and strips the upper 8 bits.

If we apply the same technique to the Size field of
EFI_COMMON_SECTION_HEADER, then the 24-bit value would be
built from reading only the 3 bytes of the array.

Best regards,
 
Mike

> -----Original Message-----
> From: devel@edk2.groups.io [mailto:devel@edk2.groups.io]
> On Behalf Of Laszlo Ersek
> Sent: Friday, April 12, 2019 4:31 PM
> To: edk2-devel-groups-io <devel@edk2.groups.io>
> Cc: Gao, Liming <liming.gao@intel.com>; Kinney, Michael
> D <michael.d.kinney@intel.com>
> Subject: [edk2-devel] [PATCH 04/10]
> MdePkg/PiFirmwareFile: fix undefined behavior in
> FFS_FILE_SIZE
> 
> Accessing "EFI_FFS_FILE_HEADER.Size", which is of type
> UINT8[3], through a
> (UINT32*), is undefined behavior. Fix it by accessing
> the array elements
> individually.
> 
> (We can't use a union here, unfortunately, as easily as
> with
> "EFI_COMMON_SECTION_HEADER", given the fields in
> "EFI_FFS_FILE_HEADER".)
> 
> Cc: Liming Gao <liming.gao@intel.com>
> Cc: Michael D Kinney <michael.d.kinney@intel.com>
> Bugzilla:
> https://bugzilla.tianocore.org/show_bug.cgi?id=1710
> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> ---
>  MdePkg/Include/Pi/PiFirmwareFile.h | 10 +++++++++-
>  1 file changed, 9 insertions(+), 1 deletion(-)
> 
> diff --git a/MdePkg/Include/Pi/PiFirmwareFile.h
> b/MdePkg/Include/Pi/PiFirmwareFile.h
> index 4fce8298d1c0..0668f3fa9af4 100644
> --- a/MdePkg/Include/Pi/PiFirmwareFile.h
> +++ b/MdePkg/Include/Pi/PiFirmwareFile.h
> @@ -174,18 +174,26 @@ typedef struct {
>    /// If FFS_ATTRIB_LARGE_FILE is not set then
> EFI_FFS_FILE_HEADER is used.
>    ///
>    UINT64                    ExtendedSize;
>  } EFI_FFS_FILE_HEADER2;
> 
>  #define IS_FFS_FILE2(FfsFileHeaderPtr) \
>      (((((EFI_FFS_FILE_HEADER *) (UINTN)
> FfsFileHeaderPtr)->Attributes) & FFS_ATTRIB_LARGE_FILE)
> == FFS_ATTRIB_LARGE_FILE)
> 
> +#define FFS_FILE_SIZE_ARRAY(FfsFileHeaderPtr) \
> +    (((EFI_FFS_FILE_HEADER *) (UINTN)
> (FfsFileHeaderPtr))->Size)
> +
> +#define FFS_FILE_SIZE_ELEMENT(FfsFileHeaderPtr, Index)
> \
> +    ((UINT32) FFS_FILE_SIZE_ARRAY
> (FfsFileHeaderPtr)[(Index)])
> +
>  #define FFS_FILE_SIZE(FfsFileHeaderPtr) \
> -    ((UINT32) (*((UINT32 *) ((EFI_FFS_FILE_HEADER *)
> (UINTN) FfsFileHeaderPtr)->Size) & 0x00ffffff))
> +    ((FFS_FILE_SIZE_ELEMENT ((FfsFileHeaderPtr), 0) <<
> 0) | \
> +     (FFS_FILE_SIZE_ELEMENT ((FfsFileHeaderPtr), 1) <<
> 8) | \
> +     (FFS_FILE_SIZE_ELEMENT ((FfsFileHeaderPtr), 2) <<
> 16))
> 
>  #define FFS_FILE2_SIZE(FfsFileHeaderPtr) \
>      ((UINT32) (((EFI_FFS_FILE_HEADER2 *) (UINTN)
> FfsFileHeaderPtr)->ExtendedSize))
> 
>  typedef UINT8 EFI_SECTION_TYPE;
> 
>  ///
>  /// Pseudo type. It is used as a wild card when
> retrieving sections.
> --
> 2.19.1.3.g30247aa5d201
> 
> 
> 
> -=-=-=-=-=-=
> Groups.io Links: You receive all messages sent to this
> group.
> 
> View/Reply Online (#38989):
> https://edk2.groups.io/g/devel/message/38989
> Mute This Topic: https://groups.io/mt/31070304/1643496
> Group Owner: devel+owner@edk2.groups.io
> Unsubscribe: https://edk2.groups.io/g/devel/unsub
> [michael.d.kinney@intel.com]
> -=-=-=-=-=-=


^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [edk2-devel] [PATCH 04/10] MdePkg/PiFirmwareFile: fix undefined behavior in FFS_FILE_SIZE
  2019-04-17 17:52   ` Michael D Kinney
@ 2019-04-17 18:31     ` Michael D Kinney
  2019-04-18  9:06       ` Laszlo Ersek
  2019-04-17 18:31     ` Andrew Fish
  2019-04-18 17:20     ` Philippe Mathieu-Daudé
  2 siblings, 1 reply; 52+ messages in thread
From: Michael D Kinney @ 2019-04-17 18:31 UTC (permalink / raw)
  To: devel@edk2.groups.io, lersek@redhat.com, Kinney, Michael D; +Cc: Gao, Liming

Laszlo,

We should also be able to do a consistent fix without
adding any new unions or macros:

#define FFS_FILE_SIZE(FfsFileHeaderPtr) ((UINT32)( \
  (((EFI_FFS_FILE_HEADER *) (UINTN) FfsFileHeaderPtr)->Size[0]       ) | \
  (((EFI_FFS_FILE_HEADER *) (UINTN) FfsFileHeaderPtr)->Size[1] << 8  ) | \
  (((EFI_FFS_FILE_HEADER *) (UINTN) FfsFileHeaderPtr)->Size[2] << 16 ) ))

#define SECTION_SIZE(SectionHeaderPtr) ((UINT32)( \
  (((EFI_COMMON_SECTION_HEADER *) (UINTN) SectionHeaderPtr)->Size[0]       ) | \
  (((EFI_COMMON_SECTION_HEADER *) (UINTN) SectionHeaderPtr)->Size[1] << 8  ) | \
  (((EFI_COMMON_SECTION_HEADER *) (UINTN) SectionHeaderPtr)->Size[2] << 16 ) ))

Best regards,

Mike

> -----Original Message-----
> From: Kinney, Michael D
> Sent: Wednesday, April 17, 2019 10:52 AM
> To: devel@edk2.groups.io; lersek@redhat.com; Kinney,
> Michael D <michael.d.kinney@intel.com>
> Cc: Gao, Liming <liming.gao@intel.com>
> Subject: RE: [edk2-devel] [PATCH 04/10]
> MdePkg/PiFirmwareFile: fix undefined behavior in
> FFS_FILE_SIZE
> 
> Laszlo,
> 
> I have been following this thread.  I think the style
> used here to access the 3 array elements to build the
> 24-bit size value is the best approach.  I prefer this
> over adding the union.
> 
> I agree there is a read overrun issue when using UINT32
> to
> read the Size[3] array contents.
> 
> I do not think this is a real issue in practice,
> because the
> Size[3] array accessed is part of the larger
> EFI_COMMON_SECTION_HEADER structure.  However, we
> always should
> clean up code to not do any read/write overruns without
> this
> type of analysis and the need to keep track of
> exceptions.
> 
> There is a related set of code in the BaseLib for
> Read/Write
> Unaligned24().
> 
> UINT32
> EFIAPI
> ReadUnaligned24 (
>   IN CONST UINT32              *Buffer
>   );
> 
> UINT32
> EFIAPI
> WriteUnaligned24 (
>   OUT UINT32                    *Buffer,
>   IN  UINT32                    Value
>   );
> 
> This API does not get flagged for read overrun issues
> because
> a UINT32 is passed in.  However, for CPU archs that
> required aligned
> access, the 24-bit value must be read in pieces.  This
> is why there
> are 2 different implementations:
> 
> IA32/X64
> ========
> UINT32
> EFIAPI
> ReadUnaligned24 (
>   IN CONST UINT32              *Buffer
>   )
> {
>   ASSERT (Buffer != NULL);
> 
>   return *Buffer & 0xffffff;
> }
> 
> 
> ARM/AARCH64
> ============
> UINT32
> EFIAPI
> ReadUnaligned24 (
>   IN CONST UINT32              *Buffer
>   )
> {
>   ASSERT (Buffer != NULL);
> 
>   return (UINT32)(
>             ReadUnaligned16 ((UINT16*)Buffer) |
>             (((UINT8*)Buffer)[2] << 16)
>             );
> }
> 
> The ARM/ARCH64 implementation is clean because it does
> not do a read overrun of the 24-bit field.  The
> IA32/X64
> implementation may have an issue because it reads a 32-
> bit
> value and strips the upper 8 bits.
> 
> If we apply the same technique to the Size field of
> EFI_COMMON_SECTION_HEADER, then the 24-bit value would
> be
> built from reading only the 3 bytes of the array.
> 
> Best regards,
> 
> Mike
> 
> > -----Original Message-----
> > From: devel@edk2.groups.io
> [mailto:devel@edk2.groups.io]
> > On Behalf Of Laszlo Ersek
> > Sent: Friday, April 12, 2019 4:31 PM
> > To: edk2-devel-groups-io <devel@edk2.groups.io>
> > Cc: Gao, Liming <liming.gao@intel.com>; Kinney,
> Michael
> > D <michael.d.kinney@intel.com>
> > Subject: [edk2-devel] [PATCH 04/10]
> > MdePkg/PiFirmwareFile: fix undefined behavior in
> > FFS_FILE_SIZE
> >
> > Accessing "EFI_FFS_FILE_HEADER.Size", which is of
> type
> > UINT8[3], through a
> > (UINT32*), is undefined behavior. Fix it by accessing
> > the array elements
> > individually.
> >
> > (We can't use a union here, unfortunately, as easily
> as
> > with
> > "EFI_COMMON_SECTION_HEADER", given the fields in
> > "EFI_FFS_FILE_HEADER".)
> >
> > Cc: Liming Gao <liming.gao@intel.com>
> > Cc: Michael D Kinney <michael.d.kinney@intel.com>
> > Bugzilla:
> > https://bugzilla.tianocore.org/show_bug.cgi?id=1710
> > Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> > ---
> >  MdePkg/Include/Pi/PiFirmwareFile.h | 10 +++++++++-
> >  1 file changed, 9 insertions(+), 1 deletion(-)
> >
> > diff --git a/MdePkg/Include/Pi/PiFirmwareFile.h
> > b/MdePkg/Include/Pi/PiFirmwareFile.h
> > index 4fce8298d1c0..0668f3fa9af4 100644
> > --- a/MdePkg/Include/Pi/PiFirmwareFile.h
> > +++ b/MdePkg/Include/Pi/PiFirmwareFile.h
> > @@ -174,18 +174,26 @@ typedef struct {
> >    /// If FFS_ATTRIB_LARGE_FILE is not set then
> > EFI_FFS_FILE_HEADER is used.
> >    ///
> >    UINT64                    ExtendedSize;
> >  } EFI_FFS_FILE_HEADER2;
> >
> >  #define IS_FFS_FILE2(FfsFileHeaderPtr) \
> >      (((((EFI_FFS_FILE_HEADER *) (UINTN)
> > FfsFileHeaderPtr)->Attributes) &
> FFS_ATTRIB_LARGE_FILE)
> > == FFS_ATTRIB_LARGE_FILE)
> >
> > +#define FFS_FILE_SIZE_ARRAY(FfsFileHeaderPtr) \
> > +    (((EFI_FFS_FILE_HEADER *) (UINTN)
> > (FfsFileHeaderPtr))->Size)
> > +
> > +#define FFS_FILE_SIZE_ELEMENT(FfsFileHeaderPtr,
> Index)
> > \
> > +    ((UINT32) FFS_FILE_SIZE_ARRAY
> > (FfsFileHeaderPtr)[(Index)])
> > +
> >  #define FFS_FILE_SIZE(FfsFileHeaderPtr) \
> > -    ((UINT32) (*((UINT32 *) ((EFI_FFS_FILE_HEADER *)
> > (UINTN) FfsFileHeaderPtr)->Size) & 0x00ffffff))
> > +    ((FFS_FILE_SIZE_ELEMENT ((FfsFileHeaderPtr), 0)
> <<
> > 0) | \
> > +     (FFS_FILE_SIZE_ELEMENT ((FfsFileHeaderPtr), 1)
> <<
> > 8) | \
> > +     (FFS_FILE_SIZE_ELEMENT ((FfsFileHeaderPtr), 2)
> <<
> > 16))
> >
> >  #define FFS_FILE2_SIZE(FfsFileHeaderPtr) \
> >      ((UINT32) (((EFI_FFS_FILE_HEADER2 *) (UINTN)
> > FfsFileHeaderPtr)->ExtendedSize))
> >
> >  typedef UINT8 EFI_SECTION_TYPE;
> >
> >  ///
> >  /// Pseudo type. It is used as a wild card when
> > retrieving sections.
> > --
> > 2.19.1.3.g30247aa5d201
> >
> >
> >
> > -=-=-=-=-=-=
> > Groups.io Links: You receive all messages sent to
> this
> > group.
> >
> > View/Reply Online (#38989):
> > https://edk2.groups.io/g/devel/message/38989
> > Mute This Topic:
> https://groups.io/mt/31070304/1643496
> > Group Owner: devel+owner@edk2.groups.io
> > Unsubscribe: https://edk2.groups.io/g/devel/unsub
> > [michael.d.kinney@intel.com]
> > -=-=-=-=-=-=


^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [edk2-devel] [PATCH 04/10] MdePkg/PiFirmwareFile: fix undefined behavior in FFS_FILE_SIZE
  2019-04-17 17:52   ` Michael D Kinney
  2019-04-17 18:31     ` Michael D Kinney
@ 2019-04-17 18:31     ` Andrew Fish
  2019-04-17 18:36       ` Michael D Kinney
  2019-04-18  8:45       ` Laszlo Ersek
  2019-04-18 17:20     ` Philippe Mathieu-Daudé
  2 siblings, 2 replies; 52+ messages in thread
From: Andrew Fish @ 2019-04-17 18:31 UTC (permalink / raw)
  To: devel, Mike Kinney; +Cc: lersek@redhat.com, Gao, Liming

[-- Attachment #1: Type: text/plain, Size: 7112 bytes --]

Mike,

I kind of ratholed us on alignment when Laszlo was more concerned about strict aliasing and the effective type rule. Sorry! I don't think your proposal fixes the effective type issue, and actually may make it worse if I'm correct. 

It seems like the safest thing to do is read byte by byte and shift which I thought we did a long time ago?

The last point I poorly tried to make to Laszlo was I thought you could cast around the effective type issue in C99. If you think about it the union and the cast are both telling the compiler the intent is to break the effective type rule and that is the bigger point I was trying to make. Given my insomnia I used alignment examples that I understand better. If we try to convert Size to a UINT32 * I think that does trigger the effect type issue Laszlo referenced. So I was only debating the boundary of enforcement of the effect type rule using alignment as a confusing example. 

I was actually writing a mail to some people that sit on the C/C++ standards committee that are UB experts to get some clarification when you sent this mail. I'm concerned I'm conflating behavior with what the standard states, and may have some recency bias with solving alignment issues that makes me think the cast should work. 

I'm basically asking if this code pedantic conforms to C99 and C11:

EFI_COMMON_SECTION_HEADER gSec = { { 0x01, 0x02, 0x3 }, 0x10 };

return *(UINT32 *)gSec.Size & 0x00ffffff;

I ran the clang static analyzer and runtime ubsan on the above code and it did not complain (I force strict aliasing via -fstrict-aliasing, and I'm using the Sys V ABI since this is just the command line compiler on my Mac). 

Thanks,

Andrew Fish

> On Apr 17, 2019, at 10:52 AM, Michael D Kinney <michael.d.kinney@intel.com> wrote:
> 
> Laszlo,
> 
> I have been following this thread.  I think the style
> used here to access the 3 array elements to build the
> 24-bit size value is the best approach.  I prefer this
> over adding the union.
> 
> I agree there is a read overrun issue when using UINT32 to
> read the Size[3] array contents.
> 
> I do not think this is a real issue in practice, because the
> Size[3] array accessed is part of the larger
> EFI_COMMON_SECTION_HEADER structure.  However, we always should
> clean up code to not do any read/write overruns without this
> type of analysis and the need to keep track of exceptions.
> 
> There is a related set of code in the BaseLib for Read/Write
> Unaligned24().
> 
> UINT32
> EFIAPI
> ReadUnaligned24 (
>  IN CONST UINT32              *Buffer
>  );
> 
> UINT32
> EFIAPI
> WriteUnaligned24 (
>  OUT UINT32                    *Buffer,
>  IN  UINT32                    Value
>  );
> 
> This API does not get flagged for read overrun issues because
> a UINT32 is passed in.  However, for CPU archs that required aligned
> access, the 24-bit value must be read in pieces.  This is why there
> are 2 different implementations:
> 
> IA32/X64
> ========
> UINT32
> EFIAPI
> ReadUnaligned24 (
>  IN CONST UINT32              *Buffer
>  )
> {
>  ASSERT (Buffer != NULL);
> 
>  return *Buffer & 0xffffff;
> }
> 
> 
> ARM/AARCH64
> ============
> UINT32
> EFIAPI
> ReadUnaligned24 (
>  IN CONST UINT32              *Buffer
>  )
> {
>  ASSERT (Buffer != NULL);
> 
>  return (UINT32)(
>            ReadUnaligned16 ((UINT16*)Buffer) |
>            (((UINT8*)Buffer)[2] << 16)
>            );
> }
> 
> The ARM/ARCH64 implementation is clean because it does
> not do a read overrun of the 24-bit field.  The IA32/X64
> implementation may have an issue because it reads a 32-bit
> value and strips the upper 8 bits.
> 
> If we apply the same technique to the Size field of
> EFI_COMMON_SECTION_HEADER, then the 24-bit value would be
> built from reading only the 3 bytes of the array.
> 
> Best regards,
> 
> Mike
> 
>> -----Original Message-----
>> From: devel@edk2.groups.io <mailto:devel@edk2.groups.io> [mailto:devel@edk2.groups.io <mailto:devel@edk2.groups.io>]
>> On Behalf Of Laszlo Ersek
>> Sent: Friday, April 12, 2019 4:31 PM
>> To: edk2-devel-groups-io <devel@edk2.groups.io <mailto:devel@edk2.groups.io>>
>> Cc: Gao, Liming <liming.gao@intel.com <mailto:liming.gao@intel.com>>; Kinney, Michael
>> D <michael.d.kinney@intel.com <mailto:michael.d.kinney@intel.com>>
>> Subject: [edk2-devel] [PATCH 04/10]
>> MdePkg/PiFirmwareFile: fix undefined behavior in
>> FFS_FILE_SIZE
>> 
>> Accessing "EFI_FFS_FILE_HEADER.Size", which is of type
>> UINT8[3], through a
>> (UINT32*), is undefined behavior. Fix it by accessing
>> the array elements
>> individually.
>> 
>> (We can't use a union here, unfortunately, as easily as
>> with
>> "EFI_COMMON_SECTION_HEADER", given the fields in
>> "EFI_FFS_FILE_HEADER".)
>> 
>> Cc: Liming Gao <liming.gao@intel.com>
>> Cc: Michael D Kinney <michael.d.kinney@intel.com>
>> Bugzilla:
>> https://bugzilla.tianocore.org/show_bug.cgi?id=1710
>> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
>> ---
>> MdePkg/Include/Pi/PiFirmwareFile.h | 10 +++++++++-
>> 1 file changed, 9 insertions(+), 1 deletion(-)
>> 
>> diff --git a/MdePkg/Include/Pi/PiFirmwareFile.h
>> b/MdePkg/Include/Pi/PiFirmwareFile.h
>> index 4fce8298d1c0..0668f3fa9af4 100644
>> --- a/MdePkg/Include/Pi/PiFirmwareFile.h
>> +++ b/MdePkg/Include/Pi/PiFirmwareFile.h
>> @@ -174,18 +174,26 @@ typedef struct {
>>   /// If FFS_ATTRIB_LARGE_FILE is not set then
>> EFI_FFS_FILE_HEADER is used.
>>   ///
>>   UINT64                    ExtendedSize;
>> } EFI_FFS_FILE_HEADER2;
>> 
>> #define IS_FFS_FILE2(FfsFileHeaderPtr) \
>>     (((((EFI_FFS_FILE_HEADER *) (UINTN)
>> FfsFileHeaderPtr)->Attributes) & FFS_ATTRIB_LARGE_FILE)
>> == FFS_ATTRIB_LARGE_FILE)
>> 
>> +#define FFS_FILE_SIZE_ARRAY(FfsFileHeaderPtr) \
>> +    (((EFI_FFS_FILE_HEADER *) (UINTN)
>> (FfsFileHeaderPtr))->Size)
>> +
>> +#define FFS_FILE_SIZE_ELEMENT(FfsFileHeaderPtr, Index)
>> \
>> +    ((UINT32) FFS_FILE_SIZE_ARRAY
>> (FfsFileHeaderPtr)[(Index)])
>> +
>> #define FFS_FILE_SIZE(FfsFileHeaderPtr) \
>> -    ((UINT32) (*((UINT32 *) ((EFI_FFS_FILE_HEADER *)
>> (UINTN) FfsFileHeaderPtr)->Size) & 0x00ffffff))
>> +    ((FFS_FILE_SIZE_ELEMENT ((FfsFileHeaderPtr), 0) <<
>> 0) | \
>> +     (FFS_FILE_SIZE_ELEMENT ((FfsFileHeaderPtr), 1) <<
>> 8) | \
>> +     (FFS_FILE_SIZE_ELEMENT ((FfsFileHeaderPtr), 2) <<
>> 16))
>> 
>> #define FFS_FILE2_SIZE(FfsFileHeaderPtr) \
>>     ((UINT32) (((EFI_FFS_FILE_HEADER2 *) (UINTN)
>> FfsFileHeaderPtr)->ExtendedSize))
>> 
>> typedef UINT8 EFI_SECTION_TYPE;
>> 
>> ///
>> /// Pseudo type. It is used as a wild card when
>> retrieving sections.
>> --
>> 2.19.1.3.g30247aa5d201
>> 
>> 
>> 
>> -=-=-=-=-=-=
>> Groups.io Links: You receive all messages sent to this
>> group.
>> 
>> View/Reply Online (#38989):
>> https://edk2.groups.io/g/devel/message/38989
>> Mute This Topic: https://groups.io/mt/31070304/1643496 <https://groups.io/mt/31070304/1643496>
>> Group Owner: devel+owner@edk2.groups.io <mailto:devel+owner@edk2.groups.io>
>> Unsubscribe: https://edk2.groups.io/g/devel/unsub <https://edk2.groups.io/g/devel/unsub>
>> [michael.d.kinney@intel.com <mailto:michael.d.kinney@intel.com>]
>> -=-=-=-=-=-=
> 
> 
> 


[-- Attachment #2: Type: text/html, Size: 63104 bytes --]

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [edk2-devel] [PATCH 04/10] MdePkg/PiFirmwareFile: fix undefined behavior in FFS_FILE_SIZE
  2019-04-17 18:31     ` Andrew Fish
@ 2019-04-17 18:36       ` Michael D Kinney
  2019-04-18  8:48         ` Laszlo Ersek
  2019-04-18  8:45       ` Laszlo Ersek
  1 sibling, 1 reply; 52+ messages in thread
From: Michael D Kinney @ 2019-04-17 18:36 UTC (permalink / raw)
  To: devel@edk2.groups.io, afish@apple.com, Kinney, Michael D
  Cc: lersek@redhat.com, Gao, Liming

[-- Attachment #1: Type: text/plain, Size: 7569 bytes --]

Andrew,

My suggestion is to read the 3 bytes and shift and or to build 24-bit value.  That is what is in the patch at the bottom.  It uses an extra layer of macros that I am not in favor of. There is an additional email with a proposed approach that makes the use of the array members more obvious.

Mike

From: devel@edk2.groups.io [mailto:devel@edk2.groups.io] On Behalf Of Andrew Fish via Groups.Io
Sent: Wednesday, April 17, 2019 11:32 AM
To: devel@edk2.groups.io; Kinney, Michael D <michael.d.kinney@intel.com>
Cc: lersek@redhat.com; Gao, Liming <liming.gao@intel.com>
Subject: Re: [edk2-devel] [PATCH 04/10] MdePkg/PiFirmwareFile: fix undefined behavior in FFS_FILE_SIZE

Mike,

I kind of ratholed us on alignment when Laszlo was more concerned about strict aliasing and the effective type rule. Sorry! I don't think your proposal fixes the effective type issue, and actually may make it worse if I'm correct.

It seems like the safest thing to do is read byte by byte and shift which I thought we did a long time ago?

The last point I poorly tried to make to Laszlo was I thought you could cast around the effective type issue in C99. If you think about it the union and the cast are both telling the compiler the intent is to break the effective type rule and that is the bigger point I was trying to make. Given my insomnia I used alignment examples that I understand better. If we try to convert Size to a UINT32 * I think that does trigger the effect type issue Laszlo referenced. So I was only debating the boundary of enforcement of the effect type rule using alignment as a confusing example.

I was actually writing a mail to some people that sit on the C/C++ standards committee that are UB experts to get some clarification when you sent this mail. I'm concerned I'm conflating behavior with what the standard states, and may have some recency bias with solving alignment issues that makes me think the cast should work.

I'm basically asking if this code pedantic conforms to C99 and C11:

EFI_COMMON_SECTION_HEADER gSec = { { 0x01, 0x02, 0x3 }, 0x10 };

return *(UINT32 *)gSec.Size & 0x00ffffff;

I ran the clang static analyzer and runtime ubsan on the above code and it did not complain (I force strict aliasing via -fstrict-aliasing, and I'm using the Sys V ABI since this is just the command line compiler on my Mac).

Thanks,

Andrew Fish


On Apr 17, 2019, at 10:52 AM, Michael D Kinney <michael.d.kinney@intel.com<mailto:michael.d.kinney@intel.com>> wrote:

Laszlo,

I have been following this thread.  I think the style
used here to access the 3 array elements to build the
24-bit size value is the best approach.  I prefer this
over adding the union.

I agree there is a read overrun issue when using UINT32 to
read the Size[3] array contents.

I do not think this is a real issue in practice, because the
Size[3] array accessed is part of the larger
EFI_COMMON_SECTION_HEADER structure.  However, we always should
clean up code to not do any read/write overruns without this
type of analysis and the need to keep track of exceptions.

There is a related set of code in the BaseLib for Read/Write
Unaligned24().

UINT32
EFIAPI
ReadUnaligned24 (
 IN CONST UINT32              *Buffer
 );

UINT32
EFIAPI
WriteUnaligned24 (
 OUT UINT32                    *Buffer,
 IN  UINT32                    Value
 );

This API does not get flagged for read overrun issues because
a UINT32 is passed in.  However, for CPU archs that required aligned
access, the 24-bit value must be read in pieces.  This is why there
are 2 different implementations:

IA32/X64
========
UINT32
EFIAPI
ReadUnaligned24 (
 IN CONST UINT32              *Buffer
 )
{
 ASSERT (Buffer != NULL);

 return *Buffer & 0xffffff;
}


ARM/AARCH64
============
UINT32
EFIAPI
ReadUnaligned24 (
 IN CONST UINT32              *Buffer
 )
{
 ASSERT (Buffer != NULL);

 return (UINT32)(
           ReadUnaligned16 ((UINT16*)Buffer) |
           (((UINT8*)Buffer)[2] << 16)
           );
}

The ARM/ARCH64 implementation is clean because it does
not do a read overrun of the 24-bit field.  The IA32/X64
implementation may have an issue because it reads a 32-bit
value and strips the upper 8 bits.

If we apply the same technique to the Size field of
EFI_COMMON_SECTION_HEADER, then the 24-bit value would be
built from reading only the 3 bytes of the array.

Best regards,

Mike


-----Original Message-----
From: devel@edk2.groups.io<mailto:devel@edk2.groups.io> [mailto:devel@edk2.groups.io]
On Behalf Of Laszlo Ersek
Sent: Friday, April 12, 2019 4:31 PM
To: edk2-devel-groups-io <devel@edk2.groups.io<mailto:devel@edk2.groups.io>>
Cc: Gao, Liming <liming.gao@intel.com<mailto:liming.gao@intel.com>>; Kinney, Michael
D <michael.d.kinney@intel.com<mailto:michael.d.kinney@intel.com>>
Subject: [edk2-devel] [PATCH 04/10]
MdePkg/PiFirmwareFile: fix undefined behavior in
FFS_FILE_SIZE

Accessing "EFI_FFS_FILE_HEADER.Size", which is of type
UINT8[3], through a
(UINT32*), is undefined behavior. Fix it by accessing
the array elements
individually.

(We can't use a union here, unfortunately, as easily as
with
"EFI_COMMON_SECTION_HEADER", given the fields in
"EFI_FFS_FILE_HEADER".)

Cc: Liming Gao <liming.gao@intel.com<mailto:liming.gao@intel.com>>
Cc: Michael D Kinney <michael.d.kinney@intel.com<mailto:michael.d.kinney@intel.com>>
Bugzilla:
https://bugzilla.tianocore.org/show_bug.cgi?id=1710
Signed-off-by: Laszlo Ersek <lersek@redhat.com<mailto:lersek@redhat.com>>
---
MdePkg/Include/Pi/PiFirmwareFile.h | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/MdePkg/Include/Pi/PiFirmwareFile.h
b/MdePkg/Include/Pi/PiFirmwareFile.h
index 4fce8298d1c0..0668f3fa9af4 100644
--- a/MdePkg/Include/Pi/PiFirmwareFile.h
+++ b/MdePkg/Include/Pi/PiFirmwareFile.h
@@ -174,18 +174,26 @@ typedef struct {
  /// If FFS_ATTRIB_LARGE_FILE is not set then
EFI_FFS_FILE_HEADER is used.
  ///
  UINT64                    ExtendedSize;
} EFI_FFS_FILE_HEADER2;

#define IS_FFS_FILE2(FfsFileHeaderPtr) \
    (((((EFI_FFS_FILE_HEADER *) (UINTN)
FfsFileHeaderPtr)->Attributes) & FFS_ATTRIB_LARGE_FILE)
== FFS_ATTRIB_LARGE_FILE)

+#define FFS_FILE_SIZE_ARRAY(FfsFileHeaderPtr) \
+    (((EFI_FFS_FILE_HEADER *) (UINTN)
(FfsFileHeaderPtr))->Size)
+
+#define FFS_FILE_SIZE_ELEMENT(FfsFileHeaderPtr, Index)
\
+    ((UINT32) FFS_FILE_SIZE_ARRAY
(FfsFileHeaderPtr)[(Index)])
+
#define FFS_FILE_SIZE(FfsFileHeaderPtr) \
-    ((UINT32) (*((UINT32 *) ((EFI_FFS_FILE_HEADER *)
(UINTN) FfsFileHeaderPtr)->Size) & 0x00ffffff))
+    ((FFS_FILE_SIZE_ELEMENT ((FfsFileHeaderPtr), 0) <<
0) | \
+     (FFS_FILE_SIZE_ELEMENT ((FfsFileHeaderPtr), 1) <<
8) | \
+     (FFS_FILE_SIZE_ELEMENT ((FfsFileHeaderPtr), 2) <<
16))

#define FFS_FILE2_SIZE(FfsFileHeaderPtr) \
    ((UINT32) (((EFI_FFS_FILE_HEADER2 *) (UINTN)
FfsFileHeaderPtr)->ExtendedSize))

typedef UINT8 EFI_SECTION_TYPE;

///
/// Pseudo type. It is used as a wild card when
retrieving sections.
--
2.19.1.3.g30247aa5d201



-=-=-=-=-=-=
Groups.io Links: You receive all messages sent to this
group.

View/Reply Online (#38989):
https://edk2.groups.io/g/devel/message/38989
Mute This Topic: https://groups.io/mt/31070304/1643496
Group Owner: devel+owner@edk2.groups.io<mailto:devel+owner@edk2.groups.io>
Unsubscribe: https://edk2.groups.io/g/devel/unsub
[michael.d.kinney@intel.com<mailto:michael.d.kinney@intel.com>]
-=-=-=-=-=-=






[-- Attachment #2: Type: text/html, Size: 54145 bytes --]

^ permalink raw reply related	[flat|nested] 52+ messages in thread

* Re: [edk2-devel] [PATCH 02/10] MdePkg/PiFirmwareFile: fix undefined behavior in SECTION_SIZE
  2019-04-17 14:59                   ` Laszlo Ersek
@ 2019-04-17 19:35                     ` Jordan Justen
  2019-04-18  9:38                       ` Laszlo Ersek
  0 siblings, 1 reply; 52+ messages in thread
From: Jordan Justen @ 2019-04-17 19:35 UTC (permalink / raw)
  To: Andrew Fish, Laszlo Ersek, devel; +Cc: devel, Mike Kinney, Liming Gao

On 2019-04-17 07:59:41, Laszlo Ersek wrote:
> On 04/17/19 13:44, Andrew Fish wrote:
> 
> > Sorry I digressed into the C specification discussion, and did not
> > deal with the patch in general. My point is the original code is legal
> > C code. If you lookup CWE-119 it is written as a restriction on what
> > the C language allows.
> >
> > As I mentioned casting to specific alignment is legal, as is defining
> > a structure that is pragma pack(1) that can make a UINT32 not be 4
> > byte aligned. Thus the cast created a legal UINT32 value. A cast to
> > *(UINT32 *) is different that a cast to (UINT32 *). The rules you
> > quote a triggered by the = and not the cast.
> >
> > Thus this is undefined behavior in C:
> >   UINT32 *Ub = (UINT32 *)gSection.Sec.Size;
> >   Size = *Ub & 0x00ffffff;
> >
> > And this is not Undefined behavior:
> >   UINT32 NotUb = *(UINT32 *)gSection.Sec.Size & 0x00ffffff;
> 
> I agree the 2nd snippet may not be UB due to alignment violations
> *alone*.
> 
> It is still UB due to violating the effective type rules.
> 
> > I also had a hard time interpreting what C spec was saying, but
> > talking to the people who write the compiler and ubsan cleared it up
> > for me. It also makes sense when you think about it. If you tell the
> > compiler *(UINT32 *) it can know to generate byte reads if the
> > hardware requires aligned access. If you do a (UINT32 *) that new
> > pointer no longer carries the information about the alignment
> > requirement. Thus the  *(UINT32 *) cast is like making a packed
> > structure.
> 
> Yes, I think I'm clear on how the alignment information is carried
> around, and when it is lost. In your first example above, due to us
> forming a separate (standalone) pointer, we lose the alignment
> information, and then the assignment is undefined due to an alignment
> violation. While in the second example, the alignment information is not
> lost, and the assignment is not undefined on an alignment basis *alone*.
> 
> However: the second assignment is *still* undefined, because it violates
> the effective type rules. Here's a more direct example for the same:
> 
> STATIC UINT64 mUint64;
> 
> int main(void)
> {
>   UINT16 *Uint16Ptr;
> 
>   Uint16Ptr = (UINT16 *)&mUint64;
>   *Uint16Ptr = 1;
>   return 0;
> }
> 
> The assignment to (*Uint16Ptr) is fine from the alignment perspective,
> but it is nevertheless undefined, because it breaks the effective type
> rules. Namely, UINT16 (the type used for the access) is not compatible
> with UINT64 (the effective type of mUint64).
> 
> Normally, we don't care about this situation in edk2 -- in fact we write
> loads of code like the above --, but we get away with that only because
> we force the toolchains to ignore the effective type rules. For GCC in
> particular, the option is "-fno-strict-aliasing".
> 
> The only reason I've posted this patch is that "cppcheck" (invoked as a
> part of "RH covscan") doesn't care about "-fno-strict-aliasing". And
> while "cppcheck" happens to report the overrun, and not the type
> punning, the way to remove the warning is to adhere to all the C rules
> in the expression, even though we have "-fno-strict-aliasing" in place.
> 
> > I agree the union is a good solution to CWE-119 and it better matches
> > the alignment requirement in the PI spec.
> 
> Thank you.
> 
> I'll wait a bit longer to see if Jordan accepts this 02/10 patch based
> on the most recent comments, and whether Liming or Mike accepts 04/10.
> 
> If Jordan remains unconvinced on SECTION_SIZE (in this 02/10 patch), and
> Liming or Mike are fine with 04/10, I can rework 02/10 to follow 04/10.
> 
> If Jordan remains unconvinced but Mike or Liming prefers the union, then
> we have a stalemate and I'll abandon the patch set.

I did have a (slight) concern about adding a typedef to a public
header that wasn't in the spec. It seemed like something that someone
somewhere might not like in case it could interfere with future
versions of the spec. According to Liming, we don't have to worry
about that.

Regarding the UINT32* discussion, I didn't think the union really
would make a difference vs skipping the union and casting the original
struct pointer directly to a UINT32*.

I can see Andrew's point that the union may add some alignment
assumptions to the dereference, so I can see how that does potentially
change something subtle. Maybe on some machines it will allow for more
efficient reading of the data with the (valid) alignment assumption.

I was also not seeing why you were saying it produced *undefined*
results. I don't think it does in our case, but when you point out
that we are aliasing data access, I can see how that quickly gets into
*undefined* territory from a compiler's perspective.

Anyway, given Liming's feedback that it is ok to add the union, I'm ok
with this patch.

-Jordan

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [edk2-devel] [PATCH 04/10] MdePkg/PiFirmwareFile: fix undefined behavior in FFS_FILE_SIZE
  2019-04-17 18:31     ` Andrew Fish
  2019-04-17 18:36       ` Michael D Kinney
@ 2019-04-18  8:45       ` Laszlo Ersek
  2019-04-18 23:12         ` Laszlo Ersek
  1 sibling, 1 reply; 52+ messages in thread
From: Laszlo Ersek @ 2019-04-18  8:45 UTC (permalink / raw)
  To: Andrew Fish, devel, Mike Kinney; +Cc: Gao, Liming

On 04/17/19 20:31, Andrew Fish wrote:

> I was actually writing a mail to some people that sit on the C/C++
> standards committee that are UB experts to get some clarification when
> you sent this mail. [...]
>
> I'm basically asking if this code pedantic conforms to C99 and C11:
>
> EFI_COMMON_SECTION_HEADER gSec = { { 0x01, 0x02, 0x3 }, 0x10 };
>
> return *(UINT32 *)gSec.Size & 0x00ffffff;

I'm really interested as to how they will respond!

(Because I think (see up-thread) that the code doesn't conform.)

> I ran the clang static analyzer and runtime ubsan on the above code
> and it did not complain (I force strict aliasing via
> -fstrict-aliasing, and I'm using the Sys V ABI since this is just the
> command line compiler on my Mac).

Yesterday I tried something similar with both gcc and clang (not recent
versions of them, unfortunately), and they were all too happy with the
code as well, when I thought they should have flagged it.

The options I used were:

  -fsyntax-only -Wall -Wextra -std=c99 -pedantic \
  -fstrict-aliasing -Wstrict-aliasing

Beyond that, I checked the documentation of "-fstrict-aliasing" in the
gcc manual at
<https://gcc.gnu.org/onlinedocs/gcc-8.3.0/gcc/Optimize-Options.html>. It
provides several examples; one of them is:

> Similarly, access by taking the address, casting the resulting pointer
> and dereferencing the result has undefined behavior, even if the cast
> uses a union type, e.g.:
>
> union a_union {
>   int i;
>   double d;
> };
>
> int f() {
>   double d = 3.0;
>   return ((union a_union *) &d)->i;
> }

I think the access in this example is well defined (I seem able to
deduce it using the effective type rules), and so I consider this a bug
in the gcc docs. I reached out to someone in the toolchain team at Red
Hat to confirm or disprove.

Thanks
Laszlo

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [edk2-devel] [PATCH 04/10] MdePkg/PiFirmwareFile: fix undefined behavior in FFS_FILE_SIZE
  2019-04-17 18:36       ` Michael D Kinney
@ 2019-04-18  8:48         ` Laszlo Ersek
  0 siblings, 0 replies; 52+ messages in thread
From: Laszlo Ersek @ 2019-04-18  8:48 UTC (permalink / raw)
  To: Kinney, Michael D, devel@edk2.groups.io, afish@apple.com; +Cc: Gao, Liming

On 04/17/19 20:36, Kinney, Michael D wrote:
> Andrew,
> 
> My suggestion is to read the 3 bytes and shift and or to build 24-bit value.  That is what is in the patch at the bottom.  It uses an extra layer of macros that I am not in favor of. There is an additional email with a proposed approach that makes the use of the array members more obvious.

I will rework both patches #2 and #4 to use the byte-wise accesses and
the shifting, without additional helper macros. It's valid C and it
seems to enjoy the widest acceptance. (I agree it's the easiest to
reason about.)

Thanks,
Laszlo

> 
> Mike
> 
> From: devel@edk2.groups.io [mailto:devel@edk2.groups.io] On Behalf Of Andrew Fish via Groups.Io
> Sent: Wednesday, April 17, 2019 11:32 AM
> To: devel@edk2.groups.io; Kinney, Michael D <michael.d.kinney@intel.com>
> Cc: lersek@redhat.com; Gao, Liming <liming.gao@intel.com>
> Subject: Re: [edk2-devel] [PATCH 04/10] MdePkg/PiFirmwareFile: fix undefined behavior in FFS_FILE_SIZE
> 
> Mike,
> 
> I kind of ratholed us on alignment when Laszlo was more concerned about strict aliasing and the effective type rule. Sorry! I don't think your proposal fixes the effective type issue, and actually may make it worse if I'm correct.
> 
> It seems like the safest thing to do is read byte by byte and shift which I thought we did a long time ago?
> 
> The last point I poorly tried to make to Laszlo was I thought you could cast around the effective type issue in C99. If you think about it the union and the cast are both telling the compiler the intent is to break the effective type rule and that is the bigger point I was trying to make. Given my insomnia I used alignment examples that I understand better. If we try to convert Size to a UINT32 * I think that does trigger the effect type issue Laszlo referenced. So I was only debating the boundary of enforcement of the effect type rule using alignment as a confusing example.
> 
> I was actually writing a mail to some people that sit on the C/C++ standards committee that are UB experts to get some clarification when you sent this mail. I'm concerned I'm conflating behavior with what the standard states, and may have some recency bias with solving alignment issues that makes me think the cast should work.
> 
> I'm basically asking if this code pedantic conforms to C99 and C11:
> 
> EFI_COMMON_SECTION_HEADER gSec = { { 0x01, 0x02, 0x3 }, 0x10 };
> 
> return *(UINT32 *)gSec.Size & 0x00ffffff;
> 
> I ran the clang static analyzer and runtime ubsan on the above code and it did not complain (I force strict aliasing via -fstrict-aliasing, and I'm using the Sys V ABI since this is just the command line compiler on my Mac).
> 
> Thanks,
> 
> Andrew Fish
> 
> 
> On Apr 17, 2019, at 10:52 AM, Michael D Kinney <michael.d.kinney@intel.com<mailto:michael.d.kinney@intel.com>> wrote:
> 
> Laszlo,
> 
> I have been following this thread.  I think the style
> used here to access the 3 array elements to build the
> 24-bit size value is the best approach.  I prefer this
> over adding the union.
> 
> I agree there is a read overrun issue when using UINT32 to
> read the Size[3] array contents.
> 
> I do not think this is a real issue in practice, because the
> Size[3] array accessed is part of the larger
> EFI_COMMON_SECTION_HEADER structure.  However, we always should
> clean up code to not do any read/write overruns without this
> type of analysis and the need to keep track of exceptions.
> 
> There is a related set of code in the BaseLib for Read/Write
> Unaligned24().
> 
> UINT32
> EFIAPI
> ReadUnaligned24 (
>  IN CONST UINT32              *Buffer
>  );
> 
> UINT32
> EFIAPI
> WriteUnaligned24 (
>  OUT UINT32                    *Buffer,
>  IN  UINT32                    Value
>  );
> 
> This API does not get flagged for read overrun issues because
> a UINT32 is passed in.  However, for CPU archs that required aligned
> access, the 24-bit value must be read in pieces.  This is why there
> are 2 different implementations:
> 
> IA32/X64
> ========
> UINT32
> EFIAPI
> ReadUnaligned24 (
>  IN CONST UINT32              *Buffer
>  )
> {
>  ASSERT (Buffer != NULL);
> 
>  return *Buffer & 0xffffff;
> }
> 
> 
> ARM/AARCH64
> ============
> UINT32
> EFIAPI
> ReadUnaligned24 (
>  IN CONST UINT32              *Buffer
>  )
> {
>  ASSERT (Buffer != NULL);
> 
>  return (UINT32)(
>            ReadUnaligned16 ((UINT16*)Buffer) |
>            (((UINT8*)Buffer)[2] << 16)
>            );
> }
> 
> The ARM/ARCH64 implementation is clean because it does
> not do a read overrun of the 24-bit field.  The IA32/X64
> implementation may have an issue because it reads a 32-bit
> value and strips the upper 8 bits.
> 
> If we apply the same technique to the Size field of
> EFI_COMMON_SECTION_HEADER, then the 24-bit value would be
> built from reading only the 3 bytes of the array.
> 
> Best regards,
> 
> Mike
> 
> 
> -----Original Message-----
> From: devel@edk2.groups.io<mailto:devel@edk2.groups.io> [mailto:devel@edk2.groups.io]
> On Behalf Of Laszlo Ersek
> Sent: Friday, April 12, 2019 4:31 PM
> To: edk2-devel-groups-io <devel@edk2.groups.io<mailto:devel@edk2.groups.io>>
> Cc: Gao, Liming <liming.gao@intel.com<mailto:liming.gao@intel.com>>; Kinney, Michael
> D <michael.d.kinney@intel.com<mailto:michael.d.kinney@intel.com>>
> Subject: [edk2-devel] [PATCH 04/10]
> MdePkg/PiFirmwareFile: fix undefined behavior in
> FFS_FILE_SIZE
> 
> Accessing "EFI_FFS_FILE_HEADER.Size", which is of type
> UINT8[3], through a
> (UINT32*), is undefined behavior. Fix it by accessing
> the array elements
> individually.
> 
> (We can't use a union here, unfortunately, as easily as
> with
> "EFI_COMMON_SECTION_HEADER", given the fields in
> "EFI_FFS_FILE_HEADER".)
> 
> Cc: Liming Gao <liming.gao@intel.com<mailto:liming.gao@intel.com>>
> Cc: Michael D Kinney <michael.d.kinney@intel.com<mailto:michael.d.kinney@intel.com>>
> Bugzilla:
> https://bugzilla.tianocore.org/show_bug.cgi?id=1710
> Signed-off-by: Laszlo Ersek <lersek@redhat.com<mailto:lersek@redhat.com>>
> ---
> MdePkg/Include/Pi/PiFirmwareFile.h | 10 +++++++++-
> 1 file changed, 9 insertions(+), 1 deletion(-)
> 
> diff --git a/MdePkg/Include/Pi/PiFirmwareFile.h
> b/MdePkg/Include/Pi/PiFirmwareFile.h
> index 4fce8298d1c0..0668f3fa9af4 100644
> --- a/MdePkg/Include/Pi/PiFirmwareFile.h
> +++ b/MdePkg/Include/Pi/PiFirmwareFile.h
> @@ -174,18 +174,26 @@ typedef struct {
>   /// If FFS_ATTRIB_LARGE_FILE is not set then
> EFI_FFS_FILE_HEADER is used.
>   ///
>   UINT64                    ExtendedSize;
> } EFI_FFS_FILE_HEADER2;
> 
> #define IS_FFS_FILE2(FfsFileHeaderPtr) \
>     (((((EFI_FFS_FILE_HEADER *) (UINTN)
> FfsFileHeaderPtr)->Attributes) & FFS_ATTRIB_LARGE_FILE)
> == FFS_ATTRIB_LARGE_FILE)
> 
> +#define FFS_FILE_SIZE_ARRAY(FfsFileHeaderPtr) \
> +    (((EFI_FFS_FILE_HEADER *) (UINTN)
> (FfsFileHeaderPtr))->Size)
> +
> +#define FFS_FILE_SIZE_ELEMENT(FfsFileHeaderPtr, Index)
> \
> +    ((UINT32) FFS_FILE_SIZE_ARRAY
> (FfsFileHeaderPtr)[(Index)])
> +
> #define FFS_FILE_SIZE(FfsFileHeaderPtr) \
> -    ((UINT32) (*((UINT32 *) ((EFI_FFS_FILE_HEADER *)
> (UINTN) FfsFileHeaderPtr)->Size) & 0x00ffffff))
> +    ((FFS_FILE_SIZE_ELEMENT ((FfsFileHeaderPtr), 0) <<
> 0) | \
> +     (FFS_FILE_SIZE_ELEMENT ((FfsFileHeaderPtr), 1) <<
> 8) | \
> +     (FFS_FILE_SIZE_ELEMENT ((FfsFileHeaderPtr), 2) <<
> 16))
> 
> #define FFS_FILE2_SIZE(FfsFileHeaderPtr) \
>     ((UINT32) (((EFI_FFS_FILE_HEADER2 *) (UINTN)
> FfsFileHeaderPtr)->ExtendedSize))
> 
> typedef UINT8 EFI_SECTION_TYPE;
> 
> ///
> /// Pseudo type. It is used as a wild card when
> retrieving sections.
> --
> 2.19.1.3.g30247aa5d201
> 
> 
> 
> -=-=-=-=-=-=
> Groups.io Links: You receive all messages sent to this
> group.
> 
> View/Reply Online (#38989):
> https://edk2.groups.io/g/devel/message/38989
> Mute This Topic: https://groups.io/mt/31070304/1643496
> Group Owner: devel+owner@edk2.groups.io<mailto:devel+owner@edk2.groups.io>
> Unsubscribe: https://edk2.groups.io/g/devel/unsub
> [michael.d.kinney@intel.com<mailto:michael.d.kinney@intel.com>]
> -=-=-=-=-=-=
> 
> 
> 
> 
> 
> 


^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [edk2-devel] [PATCH 04/10] MdePkg/PiFirmwareFile: fix undefined behavior in FFS_FILE_SIZE
  2019-04-17 18:31     ` Michael D Kinney
@ 2019-04-18  9:06       ` Laszlo Ersek
  0 siblings, 0 replies; 52+ messages in thread
From: Laszlo Ersek @ 2019-04-18  9:06 UTC (permalink / raw)
  To: Kinney, Michael D, devel@edk2.groups.io; +Cc: Gao, Liming

On 04/17/19 20:31, Kinney, Michael D wrote:
> Laszlo,
>
> We should also be able to do a consistent fix without
> adding any new unions or macros:
>
> #define FFS_FILE_SIZE(FfsFileHeaderPtr) ((UINT32)( \
>   (((EFI_FFS_FILE_HEADER *) (UINTN) FfsFileHeaderPtr)->Size[0]       ) | \
>   (((EFI_FFS_FILE_HEADER *) (UINTN) FfsFileHeaderPtr)->Size[1] << 8  ) | \
>   (((EFI_FFS_FILE_HEADER *) (UINTN) FfsFileHeaderPtr)->Size[2] << 16 ) ))
>
> #define SECTION_SIZE(SectionHeaderPtr) ((UINT32)( \
>   (((EFI_COMMON_SECTION_HEADER *) (UINTN) SectionHeaderPtr)->Size[0]       ) | \
>   (((EFI_COMMON_SECTION_HEADER *) (UINTN) SectionHeaderPtr)->Size[1] << 8  ) | \
>   (((EFI_COMMON_SECTION_HEADER *) (UINTN) SectionHeaderPtr)->Size[2] << 16 ) ))

I'll adopt this (see my other reply), with one small change: I think
I'll wrap "SectionHeaderPtr" in an extra set of parens.

My main reason for introducing the intermediate macros was that I wanted
to cast each UINT8 *individually* to UINT32, before applying the shift:

#define FFS_FILE_SIZE_ELEMENT(FfsFileHeaderPtr, Index) \
    ((UINT32) FFS_FILE_SIZE_ARRAY (FfsFileHeaderPtr)[(Index)])

#define FFS_FILE_SIZE(FfsFileHeaderPtr) \
    ((FFS_FILE_SIZE_ELEMENT ((FfsFileHeaderPtr), 0) <<  0) | \
     (FFS_FILE_SIZE_ELEMENT ((FfsFileHeaderPtr), 1) <<  8) | \
     (FFS_FILE_SIZE_ELEMENT ((FfsFileHeaderPtr), 2) << 16))

- Such casting is generally a good idea because UINT8 is promoted to
  INT32 as part of the integer promotions, and I consider bit-shifting
  signed integers bad hygiene (it carries a risk of undefined behavior).

- But then I felt that spelling out the same (UINT32) cast on every line
  of the expanded / flattened version of FFS_FILE_SIZE would make the
  replacement text simply too wide and hard to read. Hence the helper
  macros.

Now, in this particular case however (i.e. producing 24-bit unsigned
integers in the end), you have convinced me that casting to UINT32, as
the outermost operation only, is safe enough. Because, we never shift an
INT32 to the left by more than 16 bits, and that INT32 (pre-shift) is in
[0, UINT8_MAX] inclusive (because it comes from Size[2]). So the result
is always representable in an INT32.

... I've now also checked that no invocation of FFS_FILE_SIZE or
SECTION_SIZE in edk2 passes an argument with side effects, so evaluating
the arguments in the new macros multiple times should be safe. I might
add a new comment about this restriction.

Thanks!
Laszlo

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [edk2-devel] [PATCH 02/10] MdePkg/PiFirmwareFile: fix undefined behavior in SECTION_SIZE
  2019-04-17 19:35                     ` Jordan Justen
@ 2019-04-18  9:38                       ` Laszlo Ersek
  2019-04-18 15:18                         ` Liming Gao
  0 siblings, 1 reply; 52+ messages in thread
From: Laszlo Ersek @ 2019-04-18  9:38 UTC (permalink / raw)
  To: devel, jordan.l.justen, Andrew Fish; +Cc: Mike Kinney, Liming Gao

On 04/17/19 21:35, Jordan Justen wrote:
> On 2019-04-17 07:59:41, Laszlo Ersek wrote:
>> On 04/17/19 13:44, Andrew Fish wrote:
>>
>>> Sorry I digressed into the C specification discussion, and did not
>>> deal with the patch in general. My point is the original code is legal
>>> C code. If you lookup CWE-119 it is written as a restriction on what
>>> the C language allows.
>>>
>>> As I mentioned casting to specific alignment is legal, as is defining
>>> a structure that is pragma pack(1) that can make a UINT32 not be 4
>>> byte aligned. Thus the cast created a legal UINT32 value. A cast to
>>> *(UINT32 *) is different that a cast to (UINT32 *). The rules you
>>> quote a triggered by the = and not the cast.
>>>
>>> Thus this is undefined behavior in C:
>>>   UINT32 *Ub = (UINT32 *)gSection.Sec.Size;
>>>   Size = *Ub & 0x00ffffff;
>>>
>>> And this is not Undefined behavior:
>>>   UINT32 NotUb = *(UINT32 *)gSection.Sec.Size & 0x00ffffff;
>>
>> I agree the 2nd snippet may not be UB due to alignment violations
>> *alone*.
>>
>> It is still UB due to violating the effective type rules.
>>
>>> I also had a hard time interpreting what C spec was saying, but
>>> talking to the people who write the compiler and ubsan cleared it up
>>> for me. It also makes sense when you think about it. If you tell the
>>> compiler *(UINT32 *) it can know to generate byte reads if the
>>> hardware requires aligned access. If you do a (UINT32 *) that new
>>> pointer no longer carries the information about the alignment
>>> requirement. Thus the  *(UINT32 *) cast is like making a packed
>>> structure.
>>
>> Yes, I think I'm clear on how the alignment information is carried
>> around, and when it is lost. In your first example above, due to us
>> forming a separate (standalone) pointer, we lose the alignment
>> information, and then the assignment is undefined due to an alignment
>> violation. While in the second example, the alignment information is not
>> lost, and the assignment is not undefined on an alignment basis *alone*.
>>
>> However: the second assignment is *still* undefined, because it violates
>> the effective type rules. Here's a more direct example for the same:
>>
>> STATIC UINT64 mUint64;
>>
>> int main(void)
>> {
>>   UINT16 *Uint16Ptr;
>>
>>   Uint16Ptr = (UINT16 *)&mUint64;
>>   *Uint16Ptr = 1;
>>   return 0;
>> }
>>
>> The assignment to (*Uint16Ptr) is fine from the alignment perspective,
>> but it is nevertheless undefined, because it breaks the effective type
>> rules. Namely, UINT16 (the type used for the access) is not compatible
>> with UINT64 (the effective type of mUint64).
>>
>> Normally, we don't care about this situation in edk2 -- in fact we write
>> loads of code like the above --, but we get away with that only because
>> we force the toolchains to ignore the effective type rules. For GCC in
>> particular, the option is "-fno-strict-aliasing".
>>
>> The only reason I've posted this patch is that "cppcheck" (invoked as a
>> part of "RH covscan") doesn't care about "-fno-strict-aliasing". And
>> while "cppcheck" happens to report the overrun, and not the type
>> punning, the way to remove the warning is to adhere to all the C rules
>> in the expression, even though we have "-fno-strict-aliasing" in place.
>>
>>> I agree the union is a good solution to CWE-119 and it better matches
>>> the alignment requirement in the PI spec.
>>
>> Thank you.
>>
>> I'll wait a bit longer to see if Jordan accepts this 02/10 patch based
>> on the most recent comments, and whether Liming or Mike accepts 04/10.
>>
>> If Jordan remains unconvinced on SECTION_SIZE (in this 02/10 patch), and
>> Liming or Mike are fine with 04/10, I can rework 02/10 to follow 04/10.
>>
>> If Jordan remains unconvinced but Mike or Liming prefers the union, then
>> we have a stalemate and I'll abandon the patch set.
> 
> I did have a (slight) concern about adding a typedef to a public
> header that wasn't in the spec. It seemed like something that someone
> somewhere might not like in case it could interfere with future
> versions of the spec. According to Liming, we don't have to worry
> about that.
> 
> Regarding the UINT32* discussion, I didn't think the union really
> would make a difference vs skipping the union and casting the original
> struct pointer directly to a UINT32*.

The gcc docs on "-fstrict-aliasing" seem to suggest the same, using an
example -- but to me that example looks wrong (it seems well-defined,
based on the same rules I quoted from the standard); i.e. that looks
like a bug to me in the gcc docs. I've contacted a colleague at RH in
the toolchain team about it.

> I can see Andrew's point that the union may add some alignment
> assumptions to the dereference, so I can see how that does potentially
> change something subtle. Maybe on some machines it will allow for more
> efficient reading of the data with the (valid) alignment assumption.
> 
> I was also not seeing why you were saying it produced *undefined*
> results. I don't think it does in our case, but when you point out
> that we are aliasing data access, I can see how that quickly gets into
> *undefined* territory from a compiler's perspective.

Right, I approached this purely from the standard's perspective. The
standard says, in "4. Conformance":

1 In this International Standard, ‘‘shall’’ is to be interpreted as a
  requirement on an implementation or on a program; conversely, ‘‘shall
  not’’ is to be interpreted as a prohibition.

2 If a ‘‘shall’’ or ‘‘shall not’’ requirement that appears outside of a
  constraint is violated, the behavior is undefined. Undefined behavior
  is otherwise indicated in this International Standard by the words
  ‘‘undefined behavior’’ or by the omission of any explicit definition
  of behavior. There is no difference in emphasis among these three;
  they all describe ‘‘behavior that is undefined’’.

In this particular case, 6.5p7 goes "An object *shall* have its stored
value accessed *only* by [...]" (emphasis mine), and that paragraph
doesn't fall in a Constraints section, so 4p2 clearly applies.

That's why I called it undefined -- it might work perfectly well in
practice on all the edk2 platforms, possibly due to our carefully
selected compiler switches, but that's not what static analyzers care
about. AIUI they only care about the standard, hence my focus on the
standard for the fix.

(

Side note: the classification "outside of a constraint" in 4p2 above is
relevant because we also have:

5.1.1.3 Diagnostics

1 A conforming implementation shall produce at least one diagnostic
  message (identified in an implementation-defined manner) if a
  preprocessing translation unit or translation unit contains a
  violation of any syntax rule or constraint, even if the behavior is
  also explicitly specified as undefined or implementation-defined.
  [...]

IOW, if we break a "shall" or "shall not" that is under a Constraint,
then the compiler *must* yell at us; it cannot allow the UB to slip our
attention.

)

> Anyway, given Liming's feedback that it is ok to add the union, I'm ok
> with this patch.

Funnily enough, in parallel, Mike has expressed a preference for the
byte-wise access plus the shifting (without helper macros) :)

I don't see why Liming would dislike that, and I gather you too would
still prefer that to the union, so I'm going to incorporate it in v2.

Thank you!
Laszlo

> 
> 


^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [edk2-devel] [PATCH 00/10] patches for some warnings raised by "RH covscan"
  2019-04-12 23:31 [PATCH 00/10] patches for some warnings raised by "RH covscan" Laszlo Ersek
                   ` (10 preceding siblings ...)
  2019-04-12 23:36 ` [PATCH 00/10] patches for some warnings raised by "RH covscan" Ard Biesheuvel
@ 2019-04-18 14:20 ` Laszlo Ersek
  11 siblings, 0 replies; 52+ messages in thread
From: Laszlo Ersek @ 2019-04-18 14:20 UTC (permalink / raw)
  To: edk2-devel-groups-io
  Cc: Anthony Perard, Ard Biesheuvel, Bob Feng, Jordan Justen,
	Julien Grall, Liming Gao, Michael D Kinney, Yonghong Zhu

Based on feedback thus far:

On 04/13/19 01:31, Laszlo Ersek wrote:
> Bugzilla: https://bugzilla.tianocore.org/show_bug.cgi?id=1710
> Repo:     https://github.com/lersek/edk2.git
> Branch:   covscan_bz_1710
> 
> "covscan" is an internal service at Red Hat that lets associates run
> static analysis tools on Fedora/RHEL packages. It drives a number of
> static analyzers.
> 
> While covscan's existence is not "secret" (if you google it, you get a
> bunch of hits in the Red Hat Bugzilla), I can *not* use or offer
> covscan as a general upstream tool; for that the TianoCore community
> will have to build its own service / environment.
> 
> Anyway, "covscan" happened to drop a bunch of reports on me for...
> "reasons", and so I turned a short 10 hour workday into yet anoher
> normal 15 hour workday (stealing some free time whence there was none)
> in order to do something, up-stream, about the warnings that affected
> OvmfPkg. No claim is made about the completeness of the scan's
> coverage.
> 
> Some of the patches seek to suppress warnings, some strive to remedy
> valid-looking issues. We should not spend much time on this series.
> 
> Cc: Anthony Perard <anthony.perard@citrix.com>
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Cc: Bob Feng <bob.c.feng@intel.com>
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Julien Grall <julien.grall@arm.com>
> Cc: Liming Gao <liming.gao@intel.com>
> Cc: Michael D Kinney <michael.d.kinney@intel.com>
> Cc: Yonghong Zhu <yonghong.zhu@intel.com>
> 
> Thanks
> Laszlo
> 
> Laszlo Ersek (10):

I'll submit a v2 subseries with the first 5 patches:

>   MdePkg/PiFirmwareFile: express IS_SECTION2 in terms of SECTION_SIZE
>   MdePkg/PiFirmwareFile: fix undefined behavior in SECTION_SIZE
>   BaseTools/PiFirmwareFile: fix undefined behavior in SECTION_SIZE
>   MdePkg/PiFirmwareFile: fix undefined behavior in FFS_FILE_SIZE
>   OvmfPkg/Sec: fix out-of-bounds reads

This is because patches 2 through 4 have to be reworked, and patches 1
and 5 make no real sense without 2-4.

Regarding the rest (6-10):

>   OvmfPkg/QemuVideoDxe: avoid arithmetic on null pointer
>   OvmfPkg/AcpiPlatformDxe: suppress invalid "deref of undef pointer"
>     warning
>   OvmfPkg: suppress "Value stored to ... is never read" analyzer
>     warnings
>   OvmfPkg/AcpiPlatformDxe: catch theoretical nullptr deref in Xen code
>   OvmfPkg/BasePciCapLib: suppress invalid "nullptr deref" warning

I've dropped patch 8 because both Jordan and I dislike it quite a bit,
and it only aims to suppress invalid warnings. I can do that in RH
covscan too.

I've pushed the rest (6-7 and 9-10) with Ard's A-b, and also picked up
Phil's R-b wherever he posted it (933f1990f583..c2f643479eb3):

     1  52d229238b2d OvmfPkg/QemuVideoDxe: avoid arithmetic on null pointer
     2  dc5bbf10741c OvmfPkg/AcpiPlatformDxe: suppress invalid "deref of undef pointer" warning
     3  e30991740d18 OvmfPkg/AcpiPlatformDxe: catch theoretical nullptr deref in Xen code
     4  c2f643479eb3 OvmfPkg/BasePciCapLib: suppress invalid "nullptr deref" warning

Thanks,
Laszlo

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [edk2-devel] [PATCH 02/10] MdePkg/PiFirmwareFile: fix undefined behavior in SECTION_SIZE
  2019-04-18  9:38                       ` Laszlo Ersek
@ 2019-04-18 15:18                         ` Liming Gao
  0 siblings, 0 replies; 52+ messages in thread
From: Liming Gao @ 2019-04-18 15:18 UTC (permalink / raw)
  To: Laszlo Ersek, devel@edk2.groups.io, Justen, Jordan L, Andrew Fish
  Cc: Kinney, Michael D

> -----Original Message-----
> From: Laszlo Ersek [mailto:lersek@redhat.com]
> Sent: Thursday, April 18, 2019 5:39 PM
> To: devel@edk2.groups.io; Justen, Jordan L <jordan.l.justen@intel.com>; Andrew Fish <afish@apple.com>
> Cc: Kinney, Michael D <michael.d.kinney@intel.com>; Gao, Liming <liming.gao@intel.com>
> Subject: Re: [edk2-devel] [PATCH 02/10] MdePkg/PiFirmwareFile: fix undefined behavior in SECTION_SIZE
> 
> On 04/17/19 21:35, Jordan Justen wrote:
> > On 2019-04-17 07:59:41, Laszlo Ersek wrote:
> >> On 04/17/19 13:44, Andrew Fish wrote:
> >>
> >>> Sorry I digressed into the C specification discussion, and did not
> >>> deal with the patch in general. My point is the original code is legal
> >>> C code. If you lookup CWE-119 it is written as a restriction on what
> >>> the C language allows.
> >>>
> >>> As I mentioned casting to specific alignment is legal, as is defining
> >>> a structure that is pragma pack(1) that can make a UINT32 not be 4
> >>> byte aligned. Thus the cast created a legal UINT32 value. A cast to
> >>> *(UINT32 *) is different that a cast to (UINT32 *). The rules you
> >>> quote a triggered by the = and not the cast.
> >>>
> >>> Thus this is undefined behavior in C:
> >>>   UINT32 *Ub = (UINT32 *)gSection.Sec.Size;
> >>>   Size = *Ub & 0x00ffffff;
> >>>
> >>> And this is not Undefined behavior:
> >>>   UINT32 NotUb = *(UINT32 *)gSection.Sec.Size & 0x00ffffff;
> >>
> >> I agree the 2nd snippet may not be UB due to alignment violations
> >> *alone*.
> >>
> >> It is still UB due to violating the effective type rules.
> >>
> >>> I also had a hard time interpreting what C spec was saying, but
> >>> talking to the people who write the compiler and ubsan cleared it up
> >>> for me. It also makes sense when you think about it. If you tell the
> >>> compiler *(UINT32 *) it can know to generate byte reads if the
> >>> hardware requires aligned access. If you do a (UINT32 *) that new
> >>> pointer no longer carries the information about the alignment
> >>> requirement. Thus the  *(UINT32 *) cast is like making a packed
> >>> structure.
> >>
> >> Yes, I think I'm clear on how the alignment information is carried
> >> around, and when it is lost. In your first example above, due to us
> >> forming a separate (standalone) pointer, we lose the alignment
> >> information, and then the assignment is undefined due to an alignment
> >> violation. While in the second example, the alignment information is not
> >> lost, and the assignment is not undefined on an alignment basis *alone*.
> >>
> >> However: the second assignment is *still* undefined, because it violates
> >> the effective type rules. Here's a more direct example for the same:
> >>
> >> STATIC UINT64 mUint64;
> >>
> >> int main(void)
> >> {
> >>   UINT16 *Uint16Ptr;
> >>
> >>   Uint16Ptr = (UINT16 *)&mUint64;
> >>   *Uint16Ptr = 1;
> >>   return 0;
> >> }
> >>
> >> The assignment to (*Uint16Ptr) is fine from the alignment perspective,
> >> but it is nevertheless undefined, because it breaks the effective type
> >> rules. Namely, UINT16 (the type used for the access) is not compatible
> >> with UINT64 (the effective type of mUint64).
> >>
> >> Normally, we don't care about this situation in edk2 -- in fact we write
> >> loads of code like the above --, but we get away with that only because
> >> we force the toolchains to ignore the effective type rules. For GCC in
> >> particular, the option is "-fno-strict-aliasing".
> >>
> >> The only reason I've posted this patch is that "cppcheck" (invoked as a
> >> part of "RH covscan") doesn't care about "-fno-strict-aliasing". And
> >> while "cppcheck" happens to report the overrun, and not the type
> >> punning, the way to remove the warning is to adhere to all the C rules
> >> in the expression, even though we have "-fno-strict-aliasing" in place.
> >>
> >>> I agree the union is a good solution to CWE-119 and it better matches
> >>> the alignment requirement in the PI spec.
> >>
> >> Thank you.
> >>
> >> I'll wait a bit longer to see if Jordan accepts this 02/10 patch based
> >> on the most recent comments, and whether Liming or Mike accepts 04/10.
> >>
> >> If Jordan remains unconvinced on SECTION_SIZE (in this 02/10 patch), and
> >> Liming or Mike are fine with 04/10, I can rework 02/10 to follow 04/10.
> >>
> >> If Jordan remains unconvinced but Mike or Liming prefers the union, then
> >> we have a stalemate and I'll abandon the patch set.
> >
> > I did have a (slight) concern about adding a typedef to a public
> > header that wasn't in the spec. It seemed like something that someone
> > somewhere might not like in case it could interfere with future
> > versions of the spec. According to Liming, we don't have to worry
> > about that.
> >
> > Regarding the UINT32* discussion, I didn't think the union really
> > would make a difference vs skipping the union and casting the original
> > struct pointer directly to a UINT32*.
> 
> The gcc docs on "-fstrict-aliasing" seem to suggest the same, using an
> example -- but to me that example looks wrong (it seems well-defined,
> based on the same rules I quoted from the standard); i.e. that looks
> like a bug to me in the gcc docs. I've contacted a colleague at RH in
> the toolchain team about it.
> 
> > I can see Andrew's point that the union may add some alignment
> > assumptions to the dereference, so I can see how that does potentially
> > change something subtle. Maybe on some machines it will allow for more
> > efficient reading of the data with the (valid) alignment assumption.
> >
> > I was also not seeing why you were saying it produced *undefined*
> > results. I don't think it does in our case, but when you point out
> > that we are aliasing data access, I can see how that quickly gets into
> > *undefined* territory from a compiler's perspective.
> 
> Right, I approached this purely from the standard's perspective. The
> standard says, in "4. Conformance":
> 
> 1 In this International Standard, ‘‘shall’’ is to be interpreted as a
>   requirement on an implementation or on a program; conversely, ‘‘shall
>   not’’ is to be interpreted as a prohibition.
> 
> 2 If a ‘‘shall’’ or ‘‘shall not’’ requirement that appears outside of a
>   constraint is violated, the behavior is undefined. Undefined behavior
>   is otherwise indicated in this International Standard by the words
>   ‘‘undefined behavior’’ or by the omission of any explicit definition
>   of behavior. There is no difference in emphasis among these three;
>   they all describe ‘‘behavior that is undefined’’.
> 
> In this particular case, 6.5p7 goes "An object *shall* have its stored
> value accessed *only* by [...]" (emphasis mine), and that paragraph
> doesn't fall in a Constraints section, so 4p2 clearly applies.
> 
> That's why I called it undefined -- it might work perfectly well in
> practice on all the edk2 platforms, possibly due to our carefully
> selected compiler switches, but that's not what static analyzers care
> about. AIUI they only care about the standard, hence my focus on the
> standard for the fix.
> 
> (
> 
> Side note: the classification "outside of a constraint" in 4p2 above is
> relevant because we also have:
> 
> 5.1.1.3 Diagnostics
> 
> 1 A conforming implementation shall produce at least one diagnostic
>   message (identified in an implementation-defined manner) if a
>   preprocessing translation unit or translation unit contains a
>   violation of any syntax rule or constraint, even if the behavior is
>   also explicitly specified as undefined or implementation-defined.
>   [...]
> 
> IOW, if we break a "shall" or "shall not" that is under a Constraint,
> then the compiler *must* yell at us; it cannot allow the UB to slip our
> attention.
> 
> )
> 
> > Anyway, given Liming's feedback that it is ok to add the union, I'm ok
> > with this patch.
> 
> Funnily enough, in parallel, Mike has expressed a preference for the
> byte-wise access plus the shifting (without helper macros) :)
> 
> I don't see why Liming would dislike that, and I gather you too would
> still prefer that to the union, so I'm going to incorporate it in v2.
> 
I am OK for both solution. I don't think union breaks something. I agree byte access way is the consistent solution in section header and ffs header. So, I am OK for them both.

> Thank you!
> Laszlo
> 
> > 
> >


^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [edk2-devel] [PATCH 04/10] MdePkg/PiFirmwareFile: fix undefined behavior in FFS_FILE_SIZE
  2019-04-17 17:52   ` Michael D Kinney
  2019-04-17 18:31     ` Michael D Kinney
  2019-04-17 18:31     ` Andrew Fish
@ 2019-04-18 17:20     ` Philippe Mathieu-Daudé
  2019-04-18 17:59       ` Michael D Kinney
  2 siblings, 1 reply; 52+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-04-18 17:20 UTC (permalink / raw)
  To: devel, michael.d.kinney, lersek@redhat.com; +Cc: Gao, Liming

Hi Michael,

On 4/17/19 7:52 PM, Michael D Kinney wrote:
> Laszlo,
> 
> I have been following this thread.  I think the style
> used here to access the 3 array elements to build the
> 24-bit size value is the best approach.  I prefer this
> over adding the union.
> 
> I agree there is a read overrun issue when using UINT32 to
> read the Size[3] array contents.
> 
> I do not think this is a real issue in practice, because the
> Size[3] array accessed is part of the larger
> EFI_COMMON_SECTION_HEADER structure.  However, we always should
> clean up code to not do any read/write overruns without this
> type of analysis and the need to keep track of exceptions.
> 
> There is a related set of code in the BaseLib for Read/Write
> Unaligned24().
> 
> UINT32
> EFIAPI
> ReadUnaligned24 (
>   IN CONST UINT32              *Buffer
>   );
> 
> UINT32
> EFIAPI
> WriteUnaligned24 (
>   OUT UINT32                    *Buffer,
>   IN  UINT32                    Value
>   );
> 
> This API does not get flagged for read overrun issues because
> a UINT32 is passed in.  However, for CPU archs that required aligned
> access, the 24-bit value must be read in pieces.  This is why there
> are 2 different implementations:
> 
> IA32/X64
> ========
> UINT32
> EFIAPI
> ReadUnaligned24 (
>   IN CONST UINT32              *Buffer
>   )
> {
>   ASSERT (Buffer != NULL);
> 
>   return *Buffer & 0xffffff;
> }
> 
> 
> ARM/AARCH64
> ============
> UINT32
> EFIAPI
> ReadUnaligned24 (
>   IN CONST UINT32              *Buffer
>   )
> {
>   ASSERT (Buffer != NULL);
> 
>   return (UINT32)(
>             ReadUnaligned16 ((UINT16*)Buffer) |
>             (((UINT8*)Buffer)[2] << 16)
>             );
> }
> 
> The ARM/ARCH64 implementation is clean because it does
> not do a read overrun of the 24-bit field.  The IA32/X64
> implementation may have an issue because it reads a 32-bit
> value and strips the upper 8 bits.
> 
> If we apply the same technique to the Size field of
> EFI_COMMON_SECTION_HEADER, then the 24-bit value would be
> built from reading only the 3 bytes of the array.

This ARM implementation assumes Buffer is halfword-aligned OR the
microarchitectures supports unaligned halfword access.

The 3x 8-bit accesses macro looks simpler than adding a 16-bit alignment
check on Buffer, such:

   if (Buffer & 1) {
     return (UINT32)(
             ((UINT8*)Buffer)[0] |
             (ReadUnaligned16 ((UINT16*)&(((UINT8*)Buffer)[1])) << 8)
             );
   } else {
     return (UINT32)(
             ReadUnaligned16 ((UINT16*)Buffer) |
             (((UINT8*)Buffer)[2] << 16)
             );
   }

> Best regards,
>  
> Mike
> 
>> -----Original Message-----
>> From: devel@edk2.groups.io [mailto:devel@edk2.groups.io]
>> On Behalf Of Laszlo Ersek
>> Sent: Friday, April 12, 2019 4:31 PM
>> To: edk2-devel-groups-io <devel@edk2.groups.io>
>> Cc: Gao, Liming <liming.gao@intel.com>; Kinney, Michael
>> D <michael.d.kinney@intel.com>
>> Subject: [edk2-devel] [PATCH 04/10]
>> MdePkg/PiFirmwareFile: fix undefined behavior in
>> FFS_FILE_SIZE
>>
>> Accessing "EFI_FFS_FILE_HEADER.Size", which is of type
>> UINT8[3], through a
>> (UINT32*), is undefined behavior. Fix it by accessing
>> the array elements
>> individually.
>>
>> (We can't use a union here, unfortunately, as easily as
>> with
>> "EFI_COMMON_SECTION_HEADER", given the fields in
>> "EFI_FFS_FILE_HEADER".)
>>
>> Cc: Liming Gao <liming.gao@intel.com>
>> Cc: Michael D Kinney <michael.d.kinney@intel.com>
>> Bugzilla:
>> https://bugzilla.tianocore.org/show_bug.cgi?id=1710
>> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
>> ---
>>  MdePkg/Include/Pi/PiFirmwareFile.h | 10 +++++++++-
>>  1 file changed, 9 insertions(+), 1 deletion(-)
>>
>> diff --git a/MdePkg/Include/Pi/PiFirmwareFile.h
>> b/MdePkg/Include/Pi/PiFirmwareFile.h
>> index 4fce8298d1c0..0668f3fa9af4 100644
>> --- a/MdePkg/Include/Pi/PiFirmwareFile.h
>> +++ b/MdePkg/Include/Pi/PiFirmwareFile.h
>> @@ -174,18 +174,26 @@ typedef struct {
>>    /// If FFS_ATTRIB_LARGE_FILE is not set then
>> EFI_FFS_FILE_HEADER is used.
>>    ///
>>    UINT64                    ExtendedSize;
>>  } EFI_FFS_FILE_HEADER2;
>>
>>  #define IS_FFS_FILE2(FfsFileHeaderPtr) \
>>      (((((EFI_FFS_FILE_HEADER *) (UINTN)
>> FfsFileHeaderPtr)->Attributes) & FFS_ATTRIB_LARGE_FILE)
>> == FFS_ATTRIB_LARGE_FILE)
>>
>> +#define FFS_FILE_SIZE_ARRAY(FfsFileHeaderPtr) \
>> +    (((EFI_FFS_FILE_HEADER *) (UINTN)
>> (FfsFileHeaderPtr))->Size)
>> +
>> +#define FFS_FILE_SIZE_ELEMENT(FfsFileHeaderPtr, Index)
>> \
>> +    ((UINT32) FFS_FILE_SIZE_ARRAY
>> (FfsFileHeaderPtr)[(Index)])
>> +
>>  #define FFS_FILE_SIZE(FfsFileHeaderPtr) \
>> -    ((UINT32) (*((UINT32 *) ((EFI_FFS_FILE_HEADER *)
>> (UINTN) FfsFileHeaderPtr)->Size) & 0x00ffffff))
>> +    ((FFS_FILE_SIZE_ELEMENT ((FfsFileHeaderPtr), 0) <<
>> 0) | \
>> +     (FFS_FILE_SIZE_ELEMENT ((FfsFileHeaderPtr), 1) <<
>> 8) | \
>> +     (FFS_FILE_SIZE_ELEMENT ((FfsFileHeaderPtr), 2) <<
>> 16))
>>
>>  #define FFS_FILE2_SIZE(FfsFileHeaderPtr) \
>>      ((UINT32) (((EFI_FFS_FILE_HEADER2 *) (UINTN)
>> FfsFileHeaderPtr)->ExtendedSize))
>>
>>  typedef UINT8 EFI_SECTION_TYPE;
>>
>>  ///
>>  /// Pseudo type. It is used as a wild card when
>> retrieving sections.
>> --
>> 2.19.1.3.g30247aa5d201
>>
>>
>>
>> -=-=-=-=-=-=
>> Groups.io Links: You receive all messages sent to this
>> group.
>>
>> View/Reply Online (#38989):
>> https://edk2.groups.io/g/devel/message/38989
>> Mute This Topic: https://groups.io/mt/31070304/1643496
>> Group Owner: devel+owner@edk2.groups.io
>> Unsubscribe: https://edk2.groups.io/g/devel/unsub
>> [michael.d.kinney@intel.com]
>> -=-=-=-=-=-=
> 
> 
> 
> 

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [edk2-devel] [PATCH 04/10] MdePkg/PiFirmwareFile: fix undefined behavior in FFS_FILE_SIZE
  2019-04-18 17:20     ` Philippe Mathieu-Daudé
@ 2019-04-18 17:59       ` Michael D Kinney
  2019-04-18 18:12         ` Philippe Mathieu-Daudé
  0 siblings, 1 reply; 52+ messages in thread
From: Michael D Kinney @ 2019-04-18 17:59 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, devel@edk2.groups.io,
	lersek@redhat.com, Kinney, Michael D
  Cc: Gao, Liming

Philippe,

Comments below.

Thanks,

Mike

> -----Original Message-----
> From: Philippe Mathieu-Daudé [mailto:philmd@redhat.com]
> Sent: Thursday, April 18, 2019 10:20 AM
> To: devel@edk2.groups.io; Kinney, Michael D
> <michael.d.kinney@intel.com>; lersek@redhat.com
> Cc: Gao, Liming <liming.gao@intel.com>
> Subject: Re: [edk2-devel] [PATCH 04/10]
> MdePkg/PiFirmwareFile: fix undefined behavior in
> FFS_FILE_SIZE
> 
> Hi Michael,
> 
> On 4/17/19 7:52 PM, Michael D Kinney wrote:
> > Laszlo,
> >
> > I have been following this thread.  I think the style
> > used here to access the 3 array elements to build the
> > 24-bit size value is the best approach.  I prefer
> this
> > over adding the union.
> >
> > I agree there is a read overrun issue when using
> UINT32 to
> > read the Size[3] array contents.
> >
> > I do not think this is a real issue in practice,
> because the
> > Size[3] array accessed is part of the larger
> > EFI_COMMON_SECTION_HEADER structure.  However, we
> always should
> > clean up code to not do any read/write overruns
> without this
> > type of analysis and the need to keep track of
> exceptions.
> >
> > There is a related set of code in the BaseLib for
> Read/Write
> > Unaligned24().
> >
> > UINT32
> > EFIAPI
> > ReadUnaligned24 (
> >   IN CONST UINT32              *Buffer
> >   );
> >
> > UINT32
> > EFIAPI
> > WriteUnaligned24 (
> >   OUT UINT32                    *Buffer,
> >   IN  UINT32                    Value
> >   );
> >
> > This API does not get flagged for read overrun issues
> because
> > a UINT32 is passed in.  However, for CPU archs that
> required aligned
> > access, the 24-bit value must be read in pieces.
> This is why there
> > are 2 different implementations:
> >
> > IA32/X64
> > ========
> > UINT32
> > EFIAPI
> > ReadUnaligned24 (
> >   IN CONST UINT32              *Buffer
> >   )
> > {
> >   ASSERT (Buffer != NULL);
> >
> >   return *Buffer & 0xffffff;
> > }
> >
> >
> > ARM/AARCH64
> > ============
> > UINT32
> > EFIAPI
> > ReadUnaligned24 (
> >   IN CONST UINT32              *Buffer
> >   )
> > {
> >   ASSERT (Buffer != NULL);
> >
> >   return (UINT32)(
> >             ReadUnaligned16 ((UINT16*)Buffer) |
> >             (((UINT8*)Buffer)[2] << 16)
> >             );
> > }
> >
> > The ARM/ARCH64 implementation is clean because it
> does
> > not do a read overrun of the 24-bit field.  The
> IA32/X64
> > implementation may have an issue because it reads a
> 32-bit
> > value and strips the upper 8 bits.
> >
> > If we apply the same technique to the Size field of
> > EFI_COMMON_SECTION_HEADER, then the 24-bit value
> would be
> > built from reading only the 3 bytes of the array.
> 
> This ARM implementation assumes Buffer is halfword-
> aligned OR the
> microarchitectures supports unaligned halfword access.
> 
> The 3x 8-bit accesses macro looks simpler than adding a
> 16-bit alignment
> check on Buffer, such:
> 
>    if (Buffer & 1) {
>      return (UINT32)(
>              ((UINT8*)Buffer)[0] |
>              (ReadUnaligned16
> ((UINT16*)&(((UINT8*)Buffer)[1])) << 8)
>              );
>    } else {
>      return (UINT32)(
>              ReadUnaligned16 ((UINT16*)Buffer) |
>              (((UINT8*)Buffer)[2] << 16)
>              );
>    }
> 

The ARM/AARCH64 implementation of ReadUnaligned16() just
does the byte access which will always work.  So not need
to do the 2 modes you suggest above.

UINT16
EFIAPI
ReadUnaligned16 (
  IN CONST UINT16              *Buffer
  )
{
  volatile UINT8 LowerByte;
  volatile UINT8 HigherByte;

  ASSERT (Buffer != NULL);

  LowerByte = ((UINT8*)Buffer)[0];
  HigherByte = ((UINT8*)Buffer)[1];

  return (UINT16)(LowerByte | (HigherByte << 8));
}

> > Best regards,
> >
> > Mike
> >
> >> -----Original Message-----
> >> From: devel@edk2.groups.io
> [mailto:devel@edk2.groups.io]
> >> On Behalf Of Laszlo Ersek
> >> Sent: Friday, April 12, 2019 4:31 PM
> >> To: edk2-devel-groups-io <devel@edk2.groups.io>
> >> Cc: Gao, Liming <liming.gao@intel.com>; Kinney,
> Michael
> >> D <michael.d.kinney@intel.com>
> >> Subject: [edk2-devel] [PATCH 04/10]
> >> MdePkg/PiFirmwareFile: fix undefined behavior in
> >> FFS_FILE_SIZE
> >>
> >> Accessing "EFI_FFS_FILE_HEADER.Size", which is of
> type
> >> UINT8[3], through a
> >> (UINT32*), is undefined behavior. Fix it by
> accessing
> >> the array elements
> >> individually.
> >>
> >> (We can't use a union here, unfortunately, as easily
> as
> >> with
> >> "EFI_COMMON_SECTION_HEADER", given the fields in
> >> "EFI_FFS_FILE_HEADER".)
> >>
> >> Cc: Liming Gao <liming.gao@intel.com>
> >> Cc: Michael D Kinney <michael.d.kinney@intel.com>
> >> Bugzilla:
> >> https://bugzilla.tianocore.org/show_bug.cgi?id=1710
> >> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> >> ---
> >>  MdePkg/Include/Pi/PiFirmwareFile.h | 10 +++++++++-
> >>  1 file changed, 9 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/MdePkg/Include/Pi/PiFirmwareFile.h
> >> b/MdePkg/Include/Pi/PiFirmwareFile.h
> >> index 4fce8298d1c0..0668f3fa9af4 100644
> >> --- a/MdePkg/Include/Pi/PiFirmwareFile.h
> >> +++ b/MdePkg/Include/Pi/PiFirmwareFile.h
> >> @@ -174,18 +174,26 @@ typedef struct {
> >>    /// If FFS_ATTRIB_LARGE_FILE is not set then
> >> EFI_FFS_FILE_HEADER is used.
> >>    ///
> >>    UINT64                    ExtendedSize;
> >>  } EFI_FFS_FILE_HEADER2;
> >>
> >>  #define IS_FFS_FILE2(FfsFileHeaderPtr) \
> >>      (((((EFI_FFS_FILE_HEADER *) (UINTN)
> >> FfsFileHeaderPtr)->Attributes) &
> FFS_ATTRIB_LARGE_FILE)
> >> == FFS_ATTRIB_LARGE_FILE)
> >>
> >> +#define FFS_FILE_SIZE_ARRAY(FfsFileHeaderPtr) \
> >> +    (((EFI_FFS_FILE_HEADER *) (UINTN)
> >> (FfsFileHeaderPtr))->Size)
> >> +
> >> +#define FFS_FILE_SIZE_ELEMENT(FfsFileHeaderPtr,
> Index)
> >> \
> >> +    ((UINT32) FFS_FILE_SIZE_ARRAY
> >> (FfsFileHeaderPtr)[(Index)])
> >> +
> >>  #define FFS_FILE_SIZE(FfsFileHeaderPtr) \
> >> -    ((UINT32) (*((UINT32 *) ((EFI_FFS_FILE_HEADER
> *)
> >> (UINTN) FfsFileHeaderPtr)->Size) & 0x00ffffff))
> >> +    ((FFS_FILE_SIZE_ELEMENT ((FfsFileHeaderPtr), 0)
> <<
> >> 0) | \
> >> +     (FFS_FILE_SIZE_ELEMENT ((FfsFileHeaderPtr), 1)
> <<
> >> 8) | \
> >> +     (FFS_FILE_SIZE_ELEMENT ((FfsFileHeaderPtr), 2)
> <<
> >> 16))
> >>
> >>  #define FFS_FILE2_SIZE(FfsFileHeaderPtr) \
> >>      ((UINT32) (((EFI_FFS_FILE_HEADER2 *) (UINTN)
> >> FfsFileHeaderPtr)->ExtendedSize))
> >>
> >>  typedef UINT8 EFI_SECTION_TYPE;
> >>
> >>  ///
> >>  /// Pseudo type. It is used as a wild card when
> >> retrieving sections.
> >> --
> >> 2.19.1.3.g30247aa5d201
> >>
> >>
> >>
> >> -=-=-=-=-=-=
> >> Groups.io Links: You receive all messages sent to
> this
> >> group.
> >>
> >> View/Reply Online (#38989):
> >> https://edk2.groups.io/g/devel/message/38989
> >> Mute This Topic:
> https://groups.io/mt/31070304/1643496
> >> Group Owner: devel+owner@edk2.groups.io
> >> Unsubscribe: https://edk2.groups.io/g/devel/unsub
> >> [michael.d.kinney@intel.com]
> >> -=-=-=-=-=-=
> >
> >
> > 
> >

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [edk2-devel] [PATCH 04/10] MdePkg/PiFirmwareFile: fix undefined behavior in FFS_FILE_SIZE
  2019-04-18 17:59       ` Michael D Kinney
@ 2019-04-18 18:12         ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 52+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-04-18 18:12 UTC (permalink / raw)
  To: Kinney, Michael D, devel@edk2.groups.io, lersek@redhat.com; +Cc: Gao, Liming

On 4/18/19 7:59 PM, Kinney, Michael D wrote:
> Philippe,
> 
> Comments below.
> 
> Thanks,
> 
> Mike
> 
>> -----Original Message-----
>> From: Philippe Mathieu-Daudé [mailto:philmd@redhat.com]
>> Sent: Thursday, April 18, 2019 10:20 AM
>> To: devel@edk2.groups.io; Kinney, Michael D
>> <michael.d.kinney@intel.com>; lersek@redhat.com
>> Cc: Gao, Liming <liming.gao@intel.com>
>> Subject: Re: [edk2-devel] [PATCH 04/10]
>> MdePkg/PiFirmwareFile: fix undefined behavior in
>> FFS_FILE_SIZE
>>
>> Hi Michael,
>>
>> On 4/17/19 7:52 PM, Michael D Kinney wrote:
>>> Laszlo,
>>>
>>> I have been following this thread.  I think the style
>>> used here to access the 3 array elements to build the
>>> 24-bit size value is the best approach.  I prefer
>> this
>>> over adding the union.
>>>
>>> I agree there is a read overrun issue when using
>> UINT32 to
>>> read the Size[3] array contents.
>>>
>>> I do not think this is a real issue in practice,
>> because the
>>> Size[3] array accessed is part of the larger
>>> EFI_COMMON_SECTION_HEADER structure.  However, we
>> always should
>>> clean up code to not do any read/write overruns
>> without this
>>> type of analysis and the need to keep track of
>> exceptions.
>>>
>>> There is a related set of code in the BaseLib for
>> Read/Write
>>> Unaligned24().
>>>
>>> UINT32
>>> EFIAPI
>>> ReadUnaligned24 (
>>>   IN CONST UINT32              *Buffer
>>>   );
>>>
>>> UINT32
>>> EFIAPI
>>> WriteUnaligned24 (
>>>   OUT UINT32                    *Buffer,
>>>   IN  UINT32                    Value
>>>   );
>>>
>>> This API does not get flagged for read overrun issues
>> because
>>> a UINT32 is passed in.  However, for CPU archs that
>> required aligned
>>> access, the 24-bit value must be read in pieces.
>> This is why there
>>> are 2 different implementations:
>>>
>>> IA32/X64
>>> ========
>>> UINT32
>>> EFIAPI
>>> ReadUnaligned24 (
>>>   IN CONST UINT32              *Buffer
>>>   )
>>> {
>>>   ASSERT (Buffer != NULL);
>>>
>>>   return *Buffer & 0xffffff;
>>> }
>>>
>>>
>>> ARM/AARCH64
>>> ============
>>> UINT32
>>> EFIAPI
>>> ReadUnaligned24 (
>>>   IN CONST UINT32              *Buffer
>>>   )
>>> {
>>>   ASSERT (Buffer != NULL);
>>>
>>>   return (UINT32)(
>>>             ReadUnaligned16 ((UINT16*)Buffer) |
>>>             (((UINT8*)Buffer)[2] << 16)
>>>             );
>>> }
>>>
>>> The ARM/ARCH64 implementation is clean because it
>> does
>>> not do a read overrun of the 24-bit field.  The
>> IA32/X64
>>> implementation may have an issue because it reads a
>> 32-bit
>>> value and strips the upper 8 bits.
>>>
>>> If we apply the same technique to the Size field of
>>> EFI_COMMON_SECTION_HEADER, then the 24-bit value
>> would be
>>> built from reading only the 3 bytes of the array.
>>
>> This ARM implementation assumes Buffer is halfword-
>> aligned OR the
>> microarchitectures supports unaligned halfword access.
>>
>> The 3x 8-bit accesses macro looks simpler than adding a
>> 16-bit alignment
>> check on Buffer, such:
>>
>>    if (Buffer & 1) {
>>      return (UINT32)(
>>              ((UINT8*)Buffer)[0] |
>>              (ReadUnaligned16
>> ((UINT16*)&(((UINT8*)Buffer)[1])) << 8)
>>              );
>>    } else {
>>      return (UINT32)(
>>              ReadUnaligned16 ((UINT16*)Buffer) |
>>              (((UINT8*)Buffer)[2] << 16)
>>              );
>>    }
>>
> 
> The ARM/AARCH64 implementation of ReadUnaligned16() just
> does the byte access which will always work.  So not need
> to do the 2 modes you suggest above.

I should have check that first ;)

Thanks for correcting me!

> 
> UINT16
> EFIAPI
> ReadUnaligned16 (
>   IN CONST UINT16              *Buffer
>   )
> {
>   volatile UINT8 LowerByte;
>   volatile UINT8 HigherByte;
> 
>   ASSERT (Buffer != NULL);
> 
>   LowerByte = ((UINT8*)Buffer)[0];
>   HigherByte = ((UINT8*)Buffer)[1];
> 
>   return (UINT16)(LowerByte | (HigherByte << 8));
> }
> 
>>> Best regards,
>>>
>>> Mike
>>>
>>>> -----Original Message-----
>>>> From: devel@edk2.groups.io
>> [mailto:devel@edk2.groups.io]
>>>> On Behalf Of Laszlo Ersek
>>>> Sent: Friday, April 12, 2019 4:31 PM
>>>> To: edk2-devel-groups-io <devel@edk2.groups.io>
>>>> Cc: Gao, Liming <liming.gao@intel.com>; Kinney,
>> Michael
>>>> D <michael.d.kinney@intel.com>
>>>> Subject: [edk2-devel] [PATCH 04/10]
>>>> MdePkg/PiFirmwareFile: fix undefined behavior in
>>>> FFS_FILE_SIZE
>>>>
>>>> Accessing "EFI_FFS_FILE_HEADER.Size", which is of
>> type
>>>> UINT8[3], through a
>>>> (UINT32*), is undefined behavior. Fix it by
>> accessing
>>>> the array elements
>>>> individually.
>>>>
>>>> (We can't use a union here, unfortunately, as easily
>> as
>>>> with
>>>> "EFI_COMMON_SECTION_HEADER", given the fields in
>>>> "EFI_FFS_FILE_HEADER".)
>>>>
>>>> Cc: Liming Gao <liming.gao@intel.com>
>>>> Cc: Michael D Kinney <michael.d.kinney@intel.com>
>>>> Bugzilla:
>>>> https://bugzilla.tianocore.org/show_bug.cgi?id=1710
>>>> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
>>>> ---
>>>>  MdePkg/Include/Pi/PiFirmwareFile.h | 10 +++++++++-
>>>>  1 file changed, 9 insertions(+), 1 deletion(-)
>>>>
>>>> diff --git a/MdePkg/Include/Pi/PiFirmwareFile.h
>>>> b/MdePkg/Include/Pi/PiFirmwareFile.h
>>>> index 4fce8298d1c0..0668f3fa9af4 100644
>>>> --- a/MdePkg/Include/Pi/PiFirmwareFile.h
>>>> +++ b/MdePkg/Include/Pi/PiFirmwareFile.h
>>>> @@ -174,18 +174,26 @@ typedef struct {
>>>>    /// If FFS_ATTRIB_LARGE_FILE is not set then
>>>> EFI_FFS_FILE_HEADER is used.
>>>>    ///
>>>>    UINT64                    ExtendedSize;
>>>>  } EFI_FFS_FILE_HEADER2;
>>>>
>>>>  #define IS_FFS_FILE2(FfsFileHeaderPtr) \
>>>>      (((((EFI_FFS_FILE_HEADER *) (UINTN)
>>>> FfsFileHeaderPtr)->Attributes) &
>> FFS_ATTRIB_LARGE_FILE)
>>>> == FFS_ATTRIB_LARGE_FILE)
>>>>
>>>> +#define FFS_FILE_SIZE_ARRAY(FfsFileHeaderPtr) \
>>>> +    (((EFI_FFS_FILE_HEADER *) (UINTN)
>>>> (FfsFileHeaderPtr))->Size)
>>>> +
>>>> +#define FFS_FILE_SIZE_ELEMENT(FfsFileHeaderPtr,
>> Index)
>>>> \
>>>> +    ((UINT32) FFS_FILE_SIZE_ARRAY
>>>> (FfsFileHeaderPtr)[(Index)])
>>>> +
>>>>  #define FFS_FILE_SIZE(FfsFileHeaderPtr) \
>>>> -    ((UINT32) (*((UINT32 *) ((EFI_FFS_FILE_HEADER
>> *)
>>>> (UINTN) FfsFileHeaderPtr)->Size) & 0x00ffffff))
>>>> +    ((FFS_FILE_SIZE_ELEMENT ((FfsFileHeaderPtr), 0)
>> <<
>>>> 0) | \
>>>> +     (FFS_FILE_SIZE_ELEMENT ((FfsFileHeaderPtr), 1)
>> <<
>>>> 8) | \
>>>> +     (FFS_FILE_SIZE_ELEMENT ((FfsFileHeaderPtr), 2)
>> <<
>>>> 16))
>>>>
>>>>  #define FFS_FILE2_SIZE(FfsFileHeaderPtr) \
>>>>      ((UINT32) (((EFI_FFS_FILE_HEADER2 *) (UINTN)
>>>> FfsFileHeaderPtr)->ExtendedSize))
>>>>
>>>>  typedef UINT8 EFI_SECTION_TYPE;
>>>>
>>>>  ///
>>>>  /// Pseudo type. It is used as a wild card when
>>>> retrieving sections.
>>>> --
>>>> 2.19.1.3.g30247aa5d201

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [edk2-devel] [PATCH 04/10] MdePkg/PiFirmwareFile: fix undefined behavior in FFS_FILE_SIZE
  2019-04-18  8:45       ` Laszlo Ersek
@ 2019-04-18 23:12         ` Laszlo Ersek
  0 siblings, 0 replies; 52+ messages in thread
From: Laszlo Ersek @ 2019-04-18 23:12 UTC (permalink / raw)
  To: Andrew Fish, devel, Mike Kinney; +Cc: Gao, Liming

On 04/18/19 10:45, Laszlo Ersek wrote:

> Beyond that, I checked the documentation of "-fstrict-aliasing" in the
> gcc manual at
> <https://gcc.gnu.org/onlinedocs/gcc-8.3.0/gcc/Optimize-Options.html>. It
> provides several examples; one of them is:
> 
>> Similarly, access by taking the address, casting the resulting pointer
>> and dereferencing the result has undefined behavior, even if the cast
>> uses a union type, e.g.:
>>
>> union a_union {
>>   int i;
>>   double d;
>> };
>>
>> int f() {
>>   double d = 3.0;
>>   return ((union a_union *) &d)->i;
>> }
> 
> I think the access in this example is well defined (I seem able to
> deduce it using the effective type rules), and so I consider this a bug
> in the gcc docs. I reached out to someone in the toolchain team at Red
> Hat to confirm or disprove.

I was told to file an upstream GCC BZ about this, in order to reach a
wider circle of experts. In case someone from edk2-devel would like to
monitor that BZ:

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90167

Thanks,
Laszlo

^ permalink raw reply	[flat|nested] 52+ messages in thread

end of thread, other threads:[~2019-04-18 23:12 UTC | newest]

Thread overview: 52+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-04-12 23:31 [PATCH 00/10] patches for some warnings raised by "RH covscan" Laszlo Ersek
2019-04-12 23:31 ` [PATCH 01/10] MdePkg/PiFirmwareFile: express IS_SECTION2 in terms of SECTION_SIZE Laszlo Ersek
2019-04-15 17:01   ` [edk2-devel] " Philippe Mathieu-Daudé
2019-04-12 23:31 ` [PATCH 02/10] MdePkg/PiFirmwareFile: fix undefined behavior in SECTION_SIZE Laszlo Ersek
2019-04-14  7:19   ` [edk2-devel] " Jordan Justen
2019-04-15 16:15     ` Laszlo Ersek
2019-04-16  8:28       ` Liming Gao
2019-04-16  9:04       ` Jordan Justen
2019-04-16 10:59         ` Laszlo Ersek
2019-04-16 16:50           ` Philippe Mathieu-Daudé
2019-04-17 10:08             ` Laszlo Ersek
2019-04-16 18:48           ` Jordan Justen
2019-04-16 23:25             ` Andrew Fish
2019-04-17 10:29               ` Laszlo Ersek
2019-04-17 11:44                 ` Andrew Fish
2019-04-17 14:59                   ` Laszlo Ersek
2019-04-17 19:35                     ` Jordan Justen
2019-04-18  9:38                       ` Laszlo Ersek
2019-04-18 15:18                         ` Liming Gao
2019-04-17 10:01             ` Laszlo Ersek
2019-04-12 23:31 ` [PATCH 03/10] BaseTools/PiFirmwareFile: " Laszlo Ersek
2019-04-12 23:31 ` [PATCH 04/10] MdePkg/PiFirmwareFile: fix undefined behavior in FFS_FILE_SIZE Laszlo Ersek
2019-04-15 17:23   ` [edk2-devel] " Philippe Mathieu-Daudé
2019-04-17 17:52   ` Michael D Kinney
2019-04-17 18:31     ` Michael D Kinney
2019-04-18  9:06       ` Laszlo Ersek
2019-04-17 18:31     ` Andrew Fish
2019-04-17 18:36       ` Michael D Kinney
2019-04-18  8:48         ` Laszlo Ersek
2019-04-18  8:45       ` Laszlo Ersek
2019-04-18 23:12         ` Laszlo Ersek
2019-04-18 17:20     ` Philippe Mathieu-Daudé
2019-04-18 17:59       ` Michael D Kinney
2019-04-18 18:12         ` Philippe Mathieu-Daudé
2019-04-12 23:31 ` [PATCH 05/10] OvmfPkg/Sec: fix out-of-bounds reads Laszlo Ersek
2019-04-15 17:24   ` [edk2-devel] " Philippe Mathieu-Daudé
2019-04-12 23:31 ` [PATCH 06/10] OvmfPkg/QemuVideoDxe: avoid arithmetic on null pointer Laszlo Ersek
2019-04-12 23:31 ` [PATCH 07/10] OvmfPkg/AcpiPlatformDxe: suppress invalid "deref of undef pointer" warning Laszlo Ersek
2019-04-15 17:26   ` [edk2-devel] " Philippe Mathieu-Daudé
2019-04-12 23:31 ` [PATCH 08/10] OvmfPkg: suppress "Value stored to ... is never read" analyzer warnings Laszlo Ersek
2019-04-14  8:03   ` [edk2-devel] " Jordan Justen
2019-04-15 16:25     ` Laszlo Ersek
2019-04-16  9:26       ` Jordan Justen
2019-04-16 11:44         ` Laszlo Ersek
2019-04-12 23:31 ` [PATCH 09/10] OvmfPkg/AcpiPlatformDxe: catch theoretical nullptr deref in Xen code Laszlo Ersek
2019-04-15 17:28   ` [edk2-devel] " Philippe Mathieu-Daudé
2019-04-12 23:31 ` [PATCH 10/10] OvmfPkg/BasePciCapLib: suppress invalid "nullptr deref" warning Laszlo Ersek
2019-04-15 17:31   ` [edk2-devel] " Philippe Mathieu-Daudé
2019-04-16 11:01     ` Laszlo Ersek
2019-04-12 23:36 ` [PATCH 00/10] patches for some warnings raised by "RH covscan" Ard Biesheuvel
2019-04-15 16:16   ` Laszlo Ersek
2019-04-18 14:20 ` [edk2-devel] " Laszlo Ersek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox