Full analysis: gpt_partentry can be marked as aligned8. But following are
problem:
* protocols_per_handle may return unaligned guids
* configuration_tables array may be unaligned. On efi32 every entry is 20
bytes, so guids can't be 8-byte aligned
* The worst offender is device path as it's packed, unpredictable and
contains uuids.
* Efiemu gets guid as argument and probably should be able to handle
unaligned case. So far it's x86 only and we have no mmx and co so it's not
a problem right now unless we enable ubsan.
All in all we do need packed guid type unless those are resolved. I attach
patches for testing. If they work, I'll rearrange them a bit

Le dim. 13 août 2023, 05:27, Vladimir 'phcoder' Serbinenko <
phco...@gmail.com> a écrit :

>
>
> Le dim. 13 août 2023, 00:57, Pedro Miguel Justo <pm...@texair.net> a
> écrit :
>
>>
>>
>> > On Aug 12, 2023, at 11:04, John Paul Adrian Glaubitz <
>> glaub...@physik.fu-berlin.de> wrote:
>> >
>> > Hi Daniel!
>> >
>> > On Fri, 2023-08-11 at 17:31 +0200, Daniel Kiper wrote:
>> >> On Fri, Aug 11, 2023 at 04:10:14AM -0700, Oliver Steffen wrote:
>> >>> Quoting John Paul Adrian Glaubitz (2023-08-11 10:32:17)
>> >>>> Hi Oliver!
>> >>>>
>> >>>> On Fri, 2023-05-26 at 13:35 +0200, Oliver Steffen wrote:
>> >>>>> There are 3 implementations of a GUID in Grub. Replace them with a
>> >>>>> common one, placed in types.h.
>> >>>>>
>> >>>>> It uses the "packed" flavor of the GUID structs, the alignment
>> attribute
>> >>>>> is dropped, since it is not required.
>> >>>>>
>> >>>>> Signed-off-by: Oliver Steffen <ostef...@redhat.com>
>> >>>>> Reviewed-by: Daniel Kiper <daniel.ki...@oracle.com>
>> >>
>> >> [...]
>> >>
>> >>>> According to [1], this change broke GRUB on ia64:
>> >>>>
>> >>>> Welcome to GRUB!
>> >>>>
>> >>>> 7 0 0x00006B 0x000000000000001E unexpected trap
>> >>>> 7 0 0x000066 0x000000000000001E trap taken, number in ext PE
>> >>>> 7 0 0x00003C 0x0000000000005A00 trap taken, offset in ext PE
>> >>>>
>> >>>> I assume this is because of the strict alignment requirements on
>> ia64.
>> >>>>
>> >>>> Could you have a look?
>> >>>
>> >>> I am very sorry for this mistake.
>> >>> My goal was to unify the two GUID types we had in grub but I missed
>> the
>> >>> fact that in my "solution" the alignments are not correct in all
>> cases.
>> >>>
>> >>> The quickest way out could be to revert the GUID unification and
>> printf
>> >>> format specifier commits:
>> >>>
>> >>> 6ad116e5f guid: Make use of GUID printf format specifier
>> >>> f82dbf2bd kern/misc: Add a format specifier GUIDs
>> >>> 06edd40db guid: Unify GUID types
>> >>>
>> >>> And use the explicit, long-winded format string for printing the GUID
>> >>> in the bli module instead (added in the commits following those).
>> >>>
>> >>> I am open to suggestions / comments.
>> >>
>> >> Adrian, could you check what will happen when you add alignment to the
>> >> grub_guid_t as it was suggested by Frank here [2]?
>> >>
>> >> Personally I would avoid adding another GUID type with just alignment
>> >> requirement as the difference. Making one GUID type with always
>> enforced
>> >> alignment should not cost us a lot. Or we can enforce alignment on EFI
>> >> platforms only.
>> >
>> > My Itanium hardware is not available for bootloader tests at the
>> moment, so I would
>> > like to ask Pedro Miguel Justo or Frank Scheiner to test the proposed
>> fix.
>>
>>
>> The reason that before this unification there were a packed and aligned
>> types suggest that the packed type was necessary in some cases. Frank had
>> shared the concern against his own suggestion that changing the unified
>> type to be aligned (as opposite to packed) would likely regress the cases
>> where the packed might be needed/expected.
>>
>> Just for kicks, I gave it a try:
>>
>> ```
>> diff --git a/include/grub/types.h b/include/grub/types.h
>> index 0d96006fe..ff415c970 100644
>> --- a/include/grub/types.h
>> +++ b/include/grub/types.h
>> @@ -376,7 +376,7 @@ struct grub_guid
>>    grub_uint16_t data2;
>>    grub_uint16_t data3;
>>    grub_uint8_t data4[8];
>> -} GRUB_PACKED;
>> +} __attribute__ ((aligned(8)));
>>  typedef struct grub_guid grub_guid_t;
>>
>>  #endif /* ! GRUB_TYPES_HEADER */
>> ```
>>
>> As hypothesized, there are places where these structs (now unified) are
>> expected to be packed, meaning to have an alignment of 1 (even smaller than
>> the natural alignment of its larger member).
>>
>> One of the cases where the dependency is present is in the
>> grub_gpt_partentry structure. This structure is packed and includes a GUID
>> field. One struct of an enforced alignment ’n’ cannot host a member with
>> enforced alignment ‘m’ where m > n. Thus, an 8 byte aligned grub_guid
>> cannot be hosted inside a 1 byte aligned grub_gpt_partentry:
>>
>
> grub_gpt_partentry doesn't need
>
> GRUB_PACKED. To be on a safe side we can
>
> add compile time assert on its size
>
>
>
>> ```
>> In file included from grub-core/disk/ldm.c:26:
>> ./include/grub/gpt_partition.h:70:1: error: alignment 1 of ‘struct
>> grub_gpt_partentry’ is less than 8 [-Werror=packed-not-aligned]
>>    70 | } GRUB_PACKED;
>>       | ^
>> ./include/grub/gpt_partition.h:70:1: error: alignment 1 of ‘struct
>> grub_gpt_partentry’ is less than 8 [-Werror=packed-not-aligned]
>> ```
>>
>> Now, we could go this rabbit hole on and try to hack grub_gpt_partentry,
>> or special-case the GUID inside grub_gpt_partentry to be packed… but at
>> which point will I just end up with the thing we were trying to avoid: more
>> than one definition of GUID?
>>
>> >
>> > Thanks,
>> > Adrian
>> >
>> > --
>> > .''`.  John Paul Adrian Glaubitz
>> > : :' :  Debian Developer
>> > `. `'   Physicist
>> >  `-    GPG: 62FF 8A75 84E0 2956 9546  0006 7426 3B37 F5B5 F913
>>
>>
From 2464b685824e09f9e970497e30f43860e3d40ce2 Mon Sep 17 00:00:00 2001
From: Vladimir Serbinenko <phco...@gmail.com>
Date: Sun, 13 Aug 2023 09:17:22 +0200
Subject: [PATCH 2/5] Mark grub_gpt_partentry as aligned to 8 bytes

---
 include/grub/gpt_partition.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/grub/gpt_partition.h b/include/grub/gpt_partition.h
index 19df7dfff..3c70b148d 100644
--- a/include/grub/gpt_partition.h
+++ b/include/grub/gpt_partition.h
@@ -74,7 +74,7 @@ struct grub_gpt_partentry
   grub_uint64_t end;
   grub_uint64_t attrib;
   char name[72];
-} GRUB_PACKED;
+} __attribute__((aligned(8)));
 
 grub_err_t
 grub_gpt_partition_map_iterate (grub_disk_t disk,
-- 
2.39.2

From 74d86aa1e0ec87fa017ac661f033e1566b51088d Mon Sep 17 00:00:00 2001
From: Vladimir Serbinenko <phco...@gmail.com>
Date: Sun, 13 Aug 2023 09:15:54 +0200
Subject: [PATCH 1/5] Add missing static qualifier

---
 grub-core/commands/efi/lsefi.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/grub-core/commands/efi/lsefi.c b/grub-core/commands/efi/lsefi.c
index 05e2e511e..95cba5baf 100644
--- a/grub-core/commands/efi/lsefi.c
+++ b/grub-core/commands/efi/lsefi.c
@@ -29,7 +29,7 @@
 
 GRUB_MOD_LICENSE ("GPLv3+");
 
-struct known_protocol
+static struct known_protocol
 {
   grub_guid_t guid;
   const char *name;
-- 
2.39.2

From 3cd891ec5e8c51fe9e0d4872aa426cdd1335166e Mon Sep 17 00:00:00 2001
From: Vladimir Serbinenko <phco...@gmail.com>
Date: Sun, 13 Aug 2023 09:18:53 +0200
Subject: [PATCH 4/5] Add compile time asserts for guid and gpt_partentry sizes

---
 grub-core/partmap/gpt.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/grub-core/partmap/gpt.c b/grub-core/partmap/gpt.c
index 877ceefc3..426f616ae 100644
--- a/grub-core/partmap/gpt.c
+++ b/grub-core/partmap/gpt.c
@@ -229,6 +229,9 @@ static struct grub_partition_map grub_gpt_partition_map =
 
 GRUB_MOD_INIT(part_gpt)
 {
+  COMPILE_TIME_ASSERT(sizeof(grub_guid_t) == 16);
+  COMPILE_TIME_ASSERT(sizeof(grub_packed_guid_t) == 16);
+  COMPILE_TIME_ASSERT(sizeof(struct grub_gpt_partentry) == 128);
   grub_partition_map_register (&grub_gpt_partition_map);
 }
 
-- 
2.39.2

From 580463c0194308149c5a92cd28dde0a6f40bd850 Mon Sep 17 00:00:00 2001
From: Vladimir Serbinenko <phco...@gmail.com>
Date: Sun, 13 Aug 2023 09:18:23 +0200
Subject: [PATCH 3/5] Split aligned and packed guids

---
 grub-core/commands/efi/lsefi.c    |  2 +-
 grub-core/efiemu/runtime/efiemu.c | 14 +++++++-------
 grub-core/kern/efi/efi.c          |  2 +-
 grub-core/kern/misc.c             |  2 +-
 grub-core/loader/i386/xnu.c       |  2 +-
 include/grub/efi/api.h            | 12 ++++++------
 include/grub/efiemu/efiemu.h      |  4 ++--
 include/grub/efiemu/runtime.h     |  2 +-
 include/grub/types.h              | 11 ++++++++++-
 9 files changed, 30 insertions(+), 21 deletions(-)

diff --git a/grub-core/commands/efi/lsefi.c b/grub-core/commands/efi/lsefi.c
index 95cba5baf..7b8316d41 100644
--- a/grub-core/commands/efi/lsefi.c
+++ b/grub-core/commands/efi/lsefi.c
@@ -96,7 +96,7 @@ grub_cmd_lsefi (grub_command_t cmd __attribute__ ((unused)),
       grub_efi_handle_t handle = handles[i];
       grub_efi_status_t status;
       grub_efi_uintn_t num_protocols;
-      grub_guid_t **protocols;
+      grub_packed_guid_t **protocols;
       grub_efi_device_path_t *dp;
 
       grub_printf ("Handle %p\n", handle);
diff --git a/grub-core/efiemu/runtime/efiemu.c b/grub-core/efiemu/runtime/efiemu.c
index c84b30652..b98c0f2b0 100644
--- a/grub-core/efiemu/runtime/efiemu.c
+++ b/grub-core/efiemu/runtime/efiemu.c
@@ -66,7 +66,7 @@ efiemu_convert_pointer (grub_efi_uintn_t debug_disposition,
 
 grub_efi_status_t __grub_efi_api
 efiemu_get_variable (grub_efi_char16_t *variable_name,
-		     const grub_guid_t *vendor_guid,
+		     const grub_packed_guid_t *vendor_guid,
 		     grub_efi_uint32_t *attributes,
 		     grub_efi_uintn_t *data_size,
 		     void *data);
@@ -74,11 +74,11 @@ efiemu_get_variable (grub_efi_char16_t *variable_name,
 grub_efi_status_t __grub_efi_api
 efiemu_get_next_variable_name (grub_efi_uintn_t *variable_name_size,
 			       grub_efi_char16_t *variable_name,
-			       grub_guid_t *vendor_guid);
+			       grub_packed_guid_t *vendor_guid);
 
 grub_efi_status_t __grub_efi_api
 efiemu_set_variable (grub_efi_char16_t *variable_name,
-		     const grub_guid_t *vendor_guid,
+		     const grub_packed_guid_t *vendor_guid,
 		     grub_efi_uint32_t attributes,
 		     grub_efi_uintn_t data_size,
 		     void *data);
@@ -416,7 +416,7 @@ EFI_FUNC (efiemu_convert_pointer) (grub_efi_uintn_t debug_disposition,
 
 /* Find variable by name and GUID. */
 static struct efi_variable *
-find_variable (const grub_guid_t *vendor_guid,
+find_variable (const grub_packed_guid_t *vendor_guid,
 	       grub_efi_char16_t *variable_name)
 {
   grub_uint8_t *ptr;
@@ -438,7 +438,7 @@ find_variable (const grub_guid_t *vendor_guid,
 
 grub_efi_status_t __grub_efi_api
 EFI_FUNC (efiemu_get_variable) (grub_efi_char16_t *variable_name,
-				const grub_guid_t *vendor_guid,
+				const grub_packed_guid_t *vendor_guid,
 				grub_efi_uint32_t *attributes,
 				grub_efi_uintn_t *data_size,
 				void *data)
@@ -464,7 +464,7 @@ EFI_FUNC (efiemu_get_variable) (grub_efi_char16_t *variable_name,
 grub_efi_status_t __grub_efi_api EFI_FUNC
 (efiemu_get_next_variable_name) (grub_efi_uintn_t *variable_name_size,
 				 grub_efi_char16_t *variable_name,
-				 grub_guid_t *vendor_guid)
+				 grub_packed_guid_t *vendor_guid)
 {
   struct efi_variable *efivar;
   LOG ('l');
@@ -503,7 +503,7 @@ grub_efi_status_t __grub_efi_api EFI_FUNC
 
 grub_efi_status_t __grub_efi_api
 EFI_FUNC (efiemu_set_variable) (grub_efi_char16_t *variable_name,
-				const grub_guid_t *vendor_guid,
+				const grub_packed_guid_t *vendor_guid,
 				grub_efi_uint32_t attributes,
 				grub_efi_uintn_t data_size,
 				void *data)
diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c
index 9bf4f571c..20728af6b 100644
--- a/grub-core/kern/efi/efi.c
+++ b/grub-core/kern/efi/efi.c
@@ -1039,7 +1039,7 @@ grub_efi_find_configuration_table(const grub_guid_t *target_guid)
 
   for (i = 0; i < grub_efi_system_table->num_table_entries; i++)
     {
-      grub_guid_t *guid =
+      grub_packed_guid_t *guid =
 	&grub_efi_system_table->configuration_table[i].vendor_guid;
 
       if (! grub_memcmp (guid, target_guid, sizeof (grub_guid_t)))
diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c
index 2890aad49..499d7b981 100644
--- a/grub-core/kern/misc.c
+++ b/grub-core/kern/misc.c
@@ -1068,7 +1068,7 @@ grub_vsnprintf_real (char *str, grub_size_t max_len, const char *fmt0,
 	  if (*(fmt) == 'G')
 	    {
 	      ++fmt;
-	      grub_guid_t *guid = (grub_guid_t *)(grub_addr_t) curarg;
+	      grub_packed_guid_t *guid = (grub_packed_guid_t *)(grub_addr_t) curarg;
 	      write_number (str, &count, max_len, 8, 0, '0', 'x', guid->data1);
 	      write_char (str, &count, max_len, '-');
 	      write_number (str, &count, max_len, 4, 0, '0', 'x', guid->data2);
diff --git a/grub-core/loader/i386/xnu.c b/grub-core/loader/i386/xnu.c
index 4e31ce99a..b91e2f840 100644
--- a/grub-core/loader/i386/xnu.c
+++ b/grub-core/loader/i386/xnu.c
@@ -694,7 +694,7 @@ grub_cpu_xnu_fill_devicetree (grub_uint64_t *fsbfreq_out)
     {
       void *ptr;
       struct grub_xnu_devtree_key *curkey;
-      grub_guid_t guid;
+      grub_packed_guid_t guid;
       char guidbuf[64];
 
       /* Retrieve current key. */
diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
index d3eaef3fb..d44d00ad7 100644
--- a/include/grub/efi/api.h
+++ b/include/grub/efi/api.h
@@ -730,7 +730,7 @@ typedef struct grub_efi_memory_mapped_device_path grub_efi_memory_mapped_device_
 struct grub_efi_vendor_device_path
 {
   grub_efi_device_path_t header;
-  grub_guid_t vendor_guid;
+  grub_packed_guid_t vendor_guid;
   grub_efi_uint8_t vendor_defined_data[0];
 } GRUB_PACKED;
 typedef struct grub_efi_vendor_device_path grub_efi_vendor_device_path_t;
@@ -974,7 +974,7 @@ typedef struct grub_efi_cdrom_device_path grub_efi_cdrom_device_path_t;
 struct grub_efi_vendor_media_device_path
 {
   grub_efi_device_path_t header;
-  grub_guid_t vendor_guid;
+  grub_packed_guid_t vendor_guid;
   grub_efi_uint8_t vendor_defined_data[0];
 } GRUB_PACKED;
 typedef struct grub_efi_vendor_media_device_path grub_efi_vendor_media_device_path_t;
@@ -993,7 +993,7 @@ typedef struct grub_efi_file_path_device_path grub_efi_file_path_device_path_t;
 struct grub_efi_protocol_device_path
 {
   grub_efi_device_path_t header;
-  grub_guid_t guid;
+  grub_packed_guid_t guid;
 } GRUB_PACKED;
 typedef struct grub_efi_protocol_device_path grub_efi_protocol_device_path_t;
 
@@ -1002,7 +1002,7 @@ typedef struct grub_efi_protocol_device_path grub_efi_protocol_device_path_t;
 struct grub_efi_piwg_device_path
 {
   grub_efi_device_path_t header;
-  grub_guid_t guid;
+  grub_packed_guid_t guid;
 } GRUB_PACKED;
 typedef struct grub_efi_piwg_device_path grub_efi_piwg_device_path_t;
 
@@ -1287,7 +1287,7 @@ struct grub_efi_boot_services
 
   grub_efi_status_t
   (__grub_efi_api *protocols_per_handle) (grub_efi_handle_t handle,
-					  grub_guid_t ***protocol_buffer,
+					  grub_packed_guid_t ***protocol_buffer,
 					  grub_efi_uintn_t *protocol_buffer_count);
 
   grub_efi_status_t
@@ -1386,7 +1386,7 @@ typedef struct grub_efi_runtime_services grub_efi_runtime_services_t;
 
 struct grub_efi_configuration_table
 {
-  grub_guid_t vendor_guid;
+  grub_packed_guid_t vendor_guid;
   void *vendor_table;
 } GRUB_PACKED;
 typedef struct grub_efi_configuration_table grub_efi_configuration_table_t;
diff --git a/include/grub/efiemu/efiemu.h b/include/grub/efiemu/efiemu.h
index caf0b505f..d6a868e94 100644
--- a/include/grub/efiemu/efiemu.h
+++ b/include/grub/efiemu/efiemu.h
@@ -183,13 +183,13 @@ struct grub_efiemu_configuration_table
 };
 struct grub_efiemu_configuration_table32
 {
-  grub_guid_t vendor_guid;
+  grub_packed_guid_t vendor_guid;
   grub_efi_uint32_t vendor_table;
 } GRUB_PACKED;
 typedef struct grub_efiemu_configuration_table32 grub_efiemu_configuration_table32_t;
 struct grub_efiemu_configuration_table64
 {
-  grub_guid_t vendor_guid;
+  grub_packed_guid_t vendor_guid;
   grub_efi_uint64_t vendor_table;
 } GRUB_PACKED;
 typedef struct grub_efiemu_configuration_table64 grub_efiemu_configuration_table64_t;
diff --git a/include/grub/efiemu/runtime.h b/include/grub/efiemu/runtime.h
index c9ad9fdfa..2ff429845 100644
--- a/include/grub/efiemu/runtime.h
+++ b/include/grub/efiemu/runtime.h
@@ -29,7 +29,7 @@ struct grub_efiemu_ptv_rel
 
 struct efi_variable
 {
-  grub_guid_t guid;
+  grub_packed_guid_t guid;
   grub_uint32_t namelen;
   grub_uint32_t size;
   grub_efi_uint32_t attributes;
diff --git a/include/grub/types.h b/include/grub/types.h
index 0d96006fe..4028c32bf 100644
--- a/include/grub/types.h
+++ b/include/grub/types.h
@@ -376,7 +376,16 @@ struct grub_guid
   grub_uint16_t data2;
   grub_uint16_t data3;
   grub_uint8_t data4[8];
-} GRUB_PACKED;
+} __attribute__ ((aligned(8)));
 typedef struct grub_guid grub_guid_t;
 
+struct grub_packed_guid
+{
+  grub_uint32_t data1;
+  grub_uint16_t data2;
+  grub_uint16_t data3;
+  grub_uint8_t data4[8];
+} __attribute__ ((packed));
+typedef struct grub_packed_guid grub_packed_guid_t;
+
 #endif /* ! GRUB_TYPES_HEADER */
-- 
2.39.2

From cfa21b94ee00035fbff713ea7787fcdc85e21bef Mon Sep 17 00:00:00 2001
From: Vladimir Serbinenko <phco...@gmail.com>
Date: Sun, 13 Aug 2023 09:19:02 +0200
Subject: [PATCH 5/5] Fix typo

---
 include/grub/types.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/grub/types.h b/include/grub/types.h
index 4028c32bf..c31c707e3 100644
--- a/include/grub/types.h
+++ b/include/grub/types.h
@@ -349,7 +349,7 @@ static inline void grub_set_unaligned64 (void *ptr, grub_uint64_t val)
 /*
  * The grub_absolute_pointer() macro borrows the idea from Linux kernel of using
  * RELOC_HIDE() macro to stop GCC from checking the result of pointer arithmetic
- * and also it's conversion to be inside the symbol's boundary [1]. The check
+ * and also its conversion to be inside the symbol's boundary [1]. The check
  * is sometimes false positive, especially it is controversial to emit the array
  * bounds [-Warray-bounds] warning on all hardwired literal pointers since GCC
  * 11/12 [2]. Unless a good solution can be settled, for the time being we
-- 
2.39.2

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to