Blame SOURCES/0175-fix-memory-corruption-in-pubkey-filter-over-network.patch

4fe85b
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
4fe85b
From: Andrei Borzenkov <arvidjaar@gmail.com>
4fe85b
Date: Fri, 5 Dec 2014 21:17:08 +0300
4fe85b
Subject: [PATCH] fix memory corruption in pubkey filter over network
4fe85b
4fe85b
grub_pubkey_open closed original file after it was read; it set
4fe85b
io->device to NULL to prevent grub_file_close from trying to close device.
4fe85b
But network device itself is stacked (net -> bufio); and bufio preserved
4fe85b
original netfs file which hold reference to device. grub_file_close(io)
4fe85b
called grub_bufio_close which called grub_file_close for original file.
4fe85b
grub_file_close(netfs-file) now also called grub_device_close which
4fe85b
freed file->device->net. So file structure returned by grub_pubkey_open
4fe85b
now had device->net pointed to freed memory. When later file was closed,
4fe85b
it was attempted to be freed again.
4fe85b
4fe85b
Change grub_pubkey_open to behave like other filters - preserve original
4fe85b
parent file and pass grub_file_close down to parent. In this way only the
4fe85b
original file will close device. We really need to move this logic into
4fe85b
core instead.
4fe85b
4fe85b
Also plug memory leaks in error paths on the way.
4fe85b
4fe85b
Reported-By: Robert Kliewer <robert.kliewer@gmail.com>
4fe85b
Closes: bug #43601
4fe85b
---
4fe85b
 grub-core/commands/verify.c | 72 +++++++++++++++++++++++++++++++++++++--------
4fe85b
 1 file changed, 60 insertions(+), 12 deletions(-)
4fe85b
4fe85b
diff --git a/grub-core/commands/verify.c b/grub-core/commands/verify.c
4fe85b
index 525bdd18737..d5995766b4c 100644
4fe85b
--- a/grub-core/commands/verify.c
4fe85b
+++ b/grub-core/commands/verify.c
4fe85b
@@ -33,6 +33,13 @@
4fe85b
 
4fe85b
 GRUB_MOD_LICENSE ("GPLv3+");
4fe85b
 
4fe85b
+struct grub_verified
4fe85b
+{
4fe85b
+  grub_file_t file;
4fe85b
+  void *buf;
4fe85b
+};
4fe85b
+typedef struct grub_verified *grub_verified_t;
4fe85b
+
4fe85b
 enum
4fe85b
   {
4fe85b
     OPTION_SKIP_SIG = 0
4fe85b
@@ -802,19 +809,39 @@ grub_cmd_verify_signature (grub_extcmd_context_t ctxt,
4fe85b
 
4fe85b
 static int sec = 0;
4fe85b
 
4fe85b
+static void
4fe85b
+verified_free (grub_verified_t verified)
4fe85b
+{
4fe85b
+  if (verified)
4fe85b
+    {
4fe85b
+      grub_free (verified->buf);
4fe85b
+      grub_free (verified);
4fe85b
+    }
4fe85b
+}
4fe85b
+
4fe85b
 static grub_ssize_t
4fe85b
 verified_read (struct grub_file *file, char *buf, grub_size_t len)
4fe85b
 {
4fe85b
-  grub_memcpy (buf, (char *) file->data + file->offset, len);
4fe85b
+  grub_verified_t verified = file->data;
4fe85b
+
4fe85b
+  grub_memcpy (buf, (char *) verified->buf + file->offset, len);
4fe85b
   return len;
4fe85b
 }
4fe85b
 
4fe85b
 static grub_err_t
4fe85b
 verified_close (struct grub_file *file)
4fe85b
 {
4fe85b
-  grub_free (file->data);
4fe85b
+  grub_verified_t verified = file->data;
4fe85b
+
4fe85b
+  grub_file_close (verified->file);
4fe85b
+  verified_free (verified);
4fe85b
   file->data = 0;
4fe85b
-  return GRUB_ERR_NONE;
4fe85b
+
4fe85b
+  /* device and name are freed by parent */
4fe85b
+  file->device = 0;
4fe85b
+  file->name = 0;
4fe85b
+
4fe85b
+  return grub_errno;
4fe85b
 }
4fe85b
 
4fe85b
 struct grub_fs verified_fs =
4fe85b
@@ -832,6 +859,7 @@ grub_pubkey_open (grub_file_t io, const char *filename)
4fe85b
   grub_err_t err;
4fe85b
   grub_file_filter_t curfilt[GRUB_FILE_FILTER_MAX];
4fe85b
   grub_file_t ret;
4fe85b
+  grub_verified_t verified;
4fe85b
 
4fe85b
   if (!sec)
4fe85b
     return io;
4fe85b
@@ -857,7 +885,10 @@ grub_pubkey_open (grub_file_t io, const char *filename)
4fe85b
 
4fe85b
   ret = grub_malloc (sizeof (*ret));
4fe85b
   if (!ret)
4fe85b
-    return NULL;
4fe85b
+    {
4fe85b
+      grub_file_close (sig);
4fe85b
+      return NULL;
4fe85b
+    }
4fe85b
   *ret = *io;
4fe85b
 
4fe85b
   ret->fs = &verified_fs;
4fe85b
@@ -866,29 +897,46 @@ grub_pubkey_open (grub_file_t io, const char *filename)
4fe85b
     {
4fe85b
       grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
4fe85b
 		  "big file signature isn't implemented yet");
4fe85b
+      grub_file_close (sig);
4fe85b
+      grub_free (ret);
4fe85b
+      return NULL;
4fe85b
+    }
4fe85b
+  verified = grub_malloc (sizeof (*verified));
4fe85b
+  if (!verified)
4fe85b
+    {
4fe85b
+      grub_file_close (sig);
4fe85b
+      grub_free (ret);
4fe85b
       return NULL;
4fe85b
     }
4fe85b
-  ret->data = grub_malloc (ret->size);
4fe85b
-  if (!ret->data)
4fe85b
+  verified->buf = grub_malloc (ret->size);
4fe85b
+  if (!verified->buf)
4fe85b
     {
4fe85b
+      grub_file_close (sig);
4fe85b
+      grub_free (verified);
4fe85b
       grub_free (ret);
4fe85b
       return NULL;
4fe85b
     }
4fe85b
-  if (grub_file_read (io, ret->data, ret->size) != (grub_ssize_t) ret->size)
4fe85b
+  if (grub_file_read (io, verified->buf, ret->size) != (grub_ssize_t) ret->size)
4fe85b
     {
4fe85b
       if (!grub_errno)
4fe85b
 	grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
4fe85b
 		    filename);
4fe85b
+      grub_file_close (sig);
4fe85b
+      verified_free (verified);
4fe85b
+      grub_free (ret);
4fe85b
       return NULL;
4fe85b
     }
4fe85b
 
4fe85b
-  err = grub_verify_signature_real (ret->data, ret->size, 0, sig, NULL);
4fe85b
+  err = grub_verify_signature_real (verified->buf, ret->size, 0, sig, NULL);
4fe85b
   grub_file_close (sig);
4fe85b
   if (err)
4fe85b
-    return NULL;
4fe85b
-  io->device = 0;
4fe85b
-  io->name = 0;
4fe85b
-  grub_file_close (io);
4fe85b
+    {
4fe85b
+      verified_free (verified);
4fe85b
+      grub_free (ret);
4fe85b
+      return NULL;
4fe85b
+    }
4fe85b
+  verified->file = io;
4fe85b
+  ret->data = verified;
4fe85b
   return ret;
4fe85b
 }
4fe85b