From 3ffa78a46e1cd1e3d3d41717678f654ca2489da6 Mon Sep 17 00:00:00 2001
From: Michael Chang <mchang@suse.com>
Date: Thu, 11 Apr 2019 17:14:05 +0800
Subject: [PATCH 4/8] hfsplus: Fix gcc9 error with -Waddress-of-packed-member

The catkey->name could be unaligned since the address of 'void* record'
is calculated as offset in bytes to a malloc buffer.

The fix is using aligned buffer allocated by grub_malloc for holding
the UTF16 string copied from catkey->name. And use that buffer as
argument for grub_utf16_to_utf8 to convert to UTF8 strings.

In addition, using a new copy of buffer rather than catkey->name itself
for processing the endianess conversion, we can also get rid of the hunk
restoring byte order of catkey->name to what it was previously.

[   59s] ../grub-core/fs/hfsplus.c: In function 'list_nodes':
[   59s] ../grub-core/fs/hfsplus.c:738:57: error: taking address of packed member of 'struct grub_hfsplus_catkey' may result in an unaligned pointer value [-Werror=address-of-packed-member]
[   59s]   738 |   *grub_utf16_to_utf8 ((grub_uint8_t *) filename, catkey->name,
[   59s]       |                                                   ~~~~~~^~~~~~
[   59s] ../grub-core/fs/hfsplus.c: In function 'grub_hfsplus_label':
[   59s] ../grub-core/fs/hfsplus.c:1019:57: error: taking address of packed member of 'struct grub_hfsplus_catkey' may result in an unaligned pointer value [-Werror=address-of-packed-member]
[   59s]  1019 |   *grub_utf16_to_utf8 ((grub_uint8_t *) (*label), catkey->name,
[   59s]       |                                                   ~~~~~~^~~~~~

Signed-off-by: Michael Chang <mchang@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
 grub-core/fs/hfsplus.c | 57 +++++++++++++++++++++++++++++-------------
 1 file changed, 40 insertions(+), 17 deletions(-)

Index: grub-2.02~beta2/grub-core/fs/hfsplus.c
===================================================================
--- grub-2.02~beta2.orig/grub-core/fs/hfsplus.c
+++ grub-2.02~beta2/grub-core/fs/hfsplus.c
@@ -655,6 +655,7 @@ list_nodes (void *record, void *hook_arg
   char *filename;
   int i;
   struct grub_fshelp_node *node;
+  grub_uint16_t *keyname;
   struct grub_hfsplus_catfile *fileinfo;
   enum grub_fshelp_filetype type = GRUB_FSHELP_UNKNOWN;
   struct list_nodes_ctx *ctx = hook_arg;
@@ -713,29 +714,33 @@ list_nodes (void *record, void *hook_arg
   if (! filename)
     return 0;
 
+  keyname = grub_malloc (grub_be_to_cpu16 (catkey->namelen) * sizeof (*keyname));
+  if (!keyname)
+    {
+      grub_free (filename);
+      return 0;
+    }
+
   /* Make sure the byte order of the UTF16 string is correct.  */
   for (i = 0; i < grub_be_to_cpu16 (catkey->namelen); i++)
     {
-      catkey->name[i] = grub_be_to_cpu16 (catkey->name[i]);
+      keyname[i] = grub_be_to_cpu16 (catkey->name[i]);
 
-      if (catkey->name[i] == '/')
-	catkey->name[i] = ':';
+      if (keyname[i] == '/')
+	keyname[i] = ':';
 
       /* If the name is obviously invalid, skip this node.  */
-      if (catkey->name[i] == 0)
-	return 0;
+      if (keyname[i] == 0)
+	  {
+	    grub_free (keyname);
+	    return 0;
+	  }
     }
 
-  *grub_utf16_to_utf8 ((grub_uint8_t *) filename, catkey->name,
+  *grub_utf16_to_utf8 ((grub_uint8_t *) filename, keyname,
 		       grub_be_to_cpu16 (catkey->namelen)) = '\0';
 
-  /* Restore the byte order to what it was previously.  */
-  for (i = 0; i < grub_be_to_cpu16 (catkey->namelen); i++)
-    {
-      if (catkey->name[i] == ':')
-	catkey->name[i] = '/';
-      catkey->name[i] = grub_be_to_cpu16 (catkey->name[i]);
-    }
+  grub_free (keyname);
 
   /* hfs+ is case insensitive.  */
   if (! ctx->dir->data->case_sensitive)
@@ -963,6 +968,7 @@ grub_hfsplus_label (grub_device_t device
   grub_disk_t disk = device->disk;
   struct grub_hfsplus_catkey *catkey;
   int i, label_len;
+  grub_uint16_t *label_name;
   struct grub_hfsplus_key_internal intern;
   struct grub_hfsplus_btnode *node;
   grub_disk_addr_t ptr;
@@ -991,22 +997,41 @@ grub_hfsplus_label (grub_device_t device
     grub_hfsplus_btree_recptr (&data->catalog_tree, node, ptr);
 
   label_len = grub_be_to_cpu16 (catkey->namelen);
+  label_name = grub_malloc (label_len * sizeof (*label_name));
+  if (!label_name)
+    {
+      grub_free (node);
+      grub_free (data);
+      return grub_errno;
+    }
+
   for (i = 0; i < label_len; i++)
     {
-      catkey->name[i] = grub_be_to_cpu16 (catkey->name[i]);
+      label_name[i] = grub_be_to_cpu16 (catkey->name[i]);
 
       /* If the name is obviously invalid, skip this node.  */
-      if (catkey->name[i] == 0)
-	return 0;
+      if (label_name[i] == 0)
+	{
+	  grub_free (label_name);
+	  grub_free (node);
+	  grub_free (data);
+	  return 0;
+	}
     }
 
   *label = grub_malloc (label_len * GRUB_MAX_UTF8_PER_UTF16 + 1);
   if (! *label)
-    return grub_errno;
+    {
+      grub_free (label_name);
+      grub_free (node);
+      grub_free (data);
+      return grub_errno;
+    }
 
-  *grub_utf16_to_utf8 ((grub_uint8_t *) (*label), catkey->name,
+  *grub_utf16_to_utf8 ((grub_uint8_t *) (*label), label_name,
 		       label_len) = '\0';
 
+  grub_free (label_name);
   grub_free (node);
   grub_free (data);
 
