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