From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mout01.posteo.de (mout01.posteo.de [185.67.36.65]) by mx.groups.io with SMTP id smtpd.web12.15594.1629058413733849657 for ; Sun, 15 Aug 2021 13:13:34 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@posteo.de header.s=2017 header.b=S8gYKrCW; spf=pass (domain: posteo.de, ip: 185.67.36.65, mailfrom: mhaeuser@posteo.de) Received: from submission (posteo.de [89.146.220.130]) by mout01.posteo.de (Postfix) with ESMTPS id 297BD240026 for ; Sun, 15 Aug 2021 22:13:32 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=posteo.de; s=2017; t=1629058412; bh=DnxzQJ9ZhBxzTC0Bfhra+x+WABWku5G0Dzpm1oQ/B2U=; h=From:To:Cc:Subject:Date:From; b=S8gYKrCWu/GdJrTLN6QwudNt1hTWfWce1+D6Fa2Z4bnLWITKWt+2CWp64Z+0b9UIW 4HxDWIvWQk4h6FZIj4W3NyK6FTTEVtYQxYwLmfNyYalEsSCCFEnakwIYiYtmPXJzTT +RDdAVn3wvn9HX1zgK/3gCx06+HcUhzz2OD7oQFbGsyf1UlGhmUQMokhaSYox8q7lo Z3h0vjYbGqL1lHExDS8HInO81pmgQOeeOhwxApRri5Tkv+NzpHmtW5of/TSExcG3cA YUPx3tJpbuQLOfobD2PoZYhwaQDbTErf1MNCdqpMj9Y9OZrIXa0LU28ir3frkP6xB2 ZHE+XwnXoAXIg== Received: from customer (localhost [127.0.0.1]) by submission (posteo.de) with ESMTPSA id 4GnpQM4BRdz9rxV; Sun, 15 Aug 2021 22:13:31 +0200 (CEST) From: =?UTF-8?B?TWFydmluIEjDpHVzZXI=?= To: devel@edk2.groups.io Cc: Michael D Kinney , Liming Gao , Zhiguang Liu , Vitaly Cheptsov Subject: [PATCH V2 2/3] MdePkg/Base.h: Introduce various alignment-related macros Date: Sun, 15 Aug 2021 20:11:58 +0000 Message-Id: In-Reply-To: <69c6e14c4fe944d380d38dcdb851a88f51631f86.1629057790.git.mhaeuser@posteo.de> References: <69c6e14c4fe944d380d38dcdb851a88f51631f86.1629057790.git.mhaeuser@posteo.de> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable ALIGNOF: Determining the alignment requirement of data types is crucial to ensure safe memory accesses when parsing untrusted data. IS_POW2: Determining whether a value is a power of two is important to verify whether untrusted values are valid alignment values. IS_ALIGNED: In combination with ALIGNOF data offsets can be verified. A more general version of the IS_ALIGNED macro previously defined by severa= l modules. ADDRESS_IS_ALIGNED: Variant of IS_ALIGNED for pointers and addresses. Replaces module-specific definitions throughout the codebase. ALIGN_VALUE_ADDEND: The addend to align up can be used to directly determine the required offset for data alignment. Cc: Michael D Kinney Cc: Liming Gao Cc: Zhiguang Liu Cc: Vitaly Cheptsov Signed-off-by: Marvin H=C3=A4user --- MdePkg/Include/Base.h | 90 +++++++++++++++++++- 1 file changed, 89 insertions(+), 1 deletion(-) diff --git a/MdePkg/Include/Base.h b/MdePkg/Include/Base.h index 2da08b0c787f..32d0e512e05f 100644 --- a/MdePkg/Include/Base.h +++ b/MdePkg/Include/Base.h @@ -789,6 +789,35 @@ typedef UINTN *BASE_LIST; #define OFFSET_OF(TYPE, Field) ((UINTN) &(((TYPE *)0)->Field))=0D #endif=0D =0D +/**=0D + Returns the alignment requirement of a type.=0D +=0D + @param TYPE The name of the type to retrieve the alignment requiremen= t of.=0D +=0D + @return Alignment requirement, in Bytes, of TYPE.=0D +**/=0D +#if defined(__GNUC__) || defined(__clang__) || (defined(_MSC_VER) && _MSC_= VER >=3D 1900)=0D + //=0D + // All supported versions of GCC and Clang, as well as MSVC 2015 and lat= er,=0D + // support the standard operator _Alignof.=0D + //=0D + #define ALIGNOF(TYPE) _Alignof (TYPE)=0D +#elif defined(_MSC_VER)=0D + //=0D + // Earlier versions of MSVC, at least MSVC 2008 and later, support the=0D + // vendor-extension __alignof.=0D + //=0D + #define ALIGNOF(TYPE) __alignof (TYPE)=0D +#else=0D + //=0D + // For compilers that do not support inbuilt alignof operators, use OFFS= ET_OF.=0D + // CHAR8 is known to have both a size and an alignment requirement of 1 = Byte.=0D + // As such, A must be located exactly at the offset equal to its alignme= nt=0D + // requirement.=0D + //=0D + #define ALIGNOF(TYPE) OFFSET_OF (struct { CHAR8 C; TYPE A; }, A)=0D +#endif=0D +=0D /**=0D Portable definition for compile time assertions.=0D Equivalent to C11 static_assert macro from assert.h.=0D @@ -824,6 +853,21 @@ STATIC_ASSERT (sizeof (CHAR16) =3D=3D 2, "sizeof (CHA= R16) does not meet UEFI Specif STATIC_ASSERT (sizeof (L'A') =3D=3D 2, "sizeof (L'A') does not meet UEF= I Specification Data Type requirements");=0D STATIC_ASSERT (sizeof (L"A") =3D=3D 4, "sizeof (L\"A\") does not meet U= EFI Specification Data Type requirements");=0D =0D +STATIC_ASSERT (ALIGNOF (BOOLEAN) =3D=3D sizeof (BOOLEAN), "Alignment of BO= OLEAN does not meet UEFI Specification Data Type requirements");=0D +STATIC_ASSERT (ALIGNOF (INT8) =3D=3D sizeof (INT8), "Alignment of IN= T8 does not meet UEFI Specification Data Type requirements");=0D +STATIC_ASSERT (ALIGNOF (UINT8) =3D=3D sizeof (UINT8), "Alignment of IN= T16 does not meet UEFI Specification Data Type requirements");=0D +STATIC_ASSERT (ALIGNOF (INT16) =3D=3D sizeof (INT16), "Alignment of IN= T16 does not meet UEFI Specification Data Type requirements");=0D +STATIC_ASSERT (ALIGNOF (UINT16) =3D=3D sizeof (UINT16), "Alignment of UI= NT16 does not meet UEFI Specification Data Type requirements");=0D +STATIC_ASSERT (ALIGNOF (INT32) =3D=3D sizeof (INT32), "Alignment of IN= T32 does not meet UEFI Specification Data Type requirements");=0D +STATIC_ASSERT (ALIGNOF (UINT32) =3D=3D sizeof (UINT32), "Alignment of UI= NT32 does not meet UEFI Specification Data Type requirements");=0D +STATIC_ASSERT (ALIGNOF (INT64) =3D=3D sizeof (INT64), "Alignment of IN= T64 does not meet UEFI Specification Data Type requirements");=0D +STATIC_ASSERT (ALIGNOF (UINT64) =3D=3D sizeof (UINT64), "Alignment of UI= NT64 does not meet UEFI Specification Data Type requirements");=0D +STATIC_ASSERT (ALIGNOF (CHAR8) =3D=3D sizeof (CHAR8), "Alignment of CH= AR8 does not meet UEFI Specification Data Type requirements");=0D +STATIC_ASSERT (ALIGNOF (CHAR16) =3D=3D sizeof (CHAR16), "Alignment of CH= AR16 does not meet UEFI Specification Data Type requirements");=0D +STATIC_ASSERT (ALIGNOF (INTN) =3D=3D sizeof (INTN), "Alignment of IN= TN does not meet UEFI Specification Data Type requirements");=0D +STATIC_ASSERT (ALIGNOF (UINTN) =3D=3D sizeof (UINTN), "Alignment of UI= NTN does not meet UEFI Specification Data Type requirements");=0D +STATIC_ASSERT (ALIGNOF (VOID *) =3D=3D sizeof (VOID *), "Alignment of VO= ID * does not meet UEFI Specification Data Type requirements");=0D +=0D //=0D // The following three enum types are used to verify that the compiler=0D // configuration for enum types is compliant with Section 2.3.1 of the=0D @@ -847,6 +891,10 @@ STATIC_ASSERT (sizeof (__VERIFY_UINT8_ENUM_SIZE) =3D= =3D 4, "Size of enum does not me STATIC_ASSERT (sizeof (__VERIFY_UINT16_ENUM_SIZE) =3D=3D 4, "Size of enum = does not meet UEFI Specification Data Type requirements");=0D STATIC_ASSERT (sizeof (__VERIFY_UINT32_ENUM_SIZE) =3D=3D 4, "Size of enum = does not meet UEFI Specification Data Type requirements");=0D =0D +STATIC_ASSERT (ALIGNOF (__VERIFY_UINT8_ENUM_SIZE) =3D=3D sizeof (__VERIFY= _UINT8_ENUM_SIZE), "Alignment of enum does not meet UEFI Specification Dat= a Type requirements");=0D +STATIC_ASSERT (ALIGNOF (__VERIFY_UINT16_ENUM_SIZE) =3D=3D sizeof (__VERIFY= _UINT16_ENUM_SIZE), "Alignment of enum does not meet UEFI Specification Dat= a Type requirements");=0D +STATIC_ASSERT (ALIGNOF (__VERIFY_UINT32_ENUM_SIZE) =3D=3D sizeof (__VERIFY= _UINT32_ENUM_SIZE), "Alignment of enum does not meet UEFI Specification Dat= a Type requirements");=0D +=0D /**=0D Macro that returns a pointer to the data structure that contains a speci= fied field of=0D that data structure. This is a lightweight method to hide information b= y placing a=0D @@ -868,6 +916,46 @@ STATIC_ASSERT (sizeof (__VERIFY_UINT32_ENUM_SIZE) =3D= =3D 4, "Size of enum does not m **/=0D #define BASE_CR(Record, TYPE, Field) ((TYPE *) ((CHAR8 *) (Record) - OFFS= ET_OF (TYPE, Field)))=0D =0D +/**=0D + Checks whether a value is a power of two.=0D +=0D + @param Value The value to check.=0D +=0D + @return Whether Value is a power of two.=0D +**/=0D +#define IS_POW2(Value) ((Value) !=3D 0U && ((Value) & ((Value) - 1U)) =3D= =3D 0U)=0D +=0D +/**=0D + Checks whether a value is aligned by a specified alignment.=0D +=0D + @param Value The value to check.=0D + @param Alignment The alignment boundary used to check against.=0D +=0D + @return Whether Value is aligned by Alignment.=0D +**/=0D +#define IS_ALIGNED(Value, Alignment) (((Value) & ((Alignment) - 1U)) =3D= =3D 0U)=0D +=0D +/**=0D + Checks whether a pointer or address is aligned by a specified alignment.= =0D +=0D + @param Address The pointer or address to check.=0D + @param Alignment The alignment boundary used to check against.=0D +=0D + @return Whether Address is aligned by Alignment.=0D +**/=0D +#define ADDRESS_IS_ALIGNED(Address, Alignment) IS_ALIGNED ((UINTN) (Addre= ss), Alignment)=0D +=0D +/**=0D + Determines the addend to add to a value to round it up to the next bound= ary of=0D + a specified alignment.=0D +=0D + @param Value The value to round up.=0D + @param Alignment The alignment boundary used to return the addend.=0D +=0D + @return Addend to round Value up to alignment boundary Alignment.=0D +**/=0D +#define ALIGN_VALUE_ADDEND(Value, Alignment) (((Alignment) - (Value)) & (= (Alignment) - 1U))=0D +=0D /**=0D Rounds a value up to the next boundary using a specified alignment.=0D =0D @@ -880,7 +968,7 @@ STATIC_ASSERT (sizeof (__VERIFY_UINT32_ENUM_SIZE) =3D= =3D 4, "Size of enum does not m @return A value up to the next boundary.=0D =0D **/=0D -#define ALIGN_VALUE(Value, Alignment) ((Value) + (((Alignment) - (Value)) = & ((Alignment) - 1)))=0D +#define ALIGN_VALUE(Value, Alignment) ((Value) + ALIGN_VALUE_ADDEND (Value= , Alignment))=0D =0D /**=0D Adjust a pointer by adding the minimum offset required for it to be alig= ned on=0D --=20 2.31.1