a5bd9f6
From 2923eb14c2e0feab103391314331a13f069df813 Mon Sep 17 00:00:00 2001
a5bd9f6
From: Vladimir 'phcoder' Serbinenko <phcoder@gmail.com>
a5bd9f6
Date: Wed, 3 Apr 2013 17:32:33 +0200
a5bd9f6
Subject: [PATCH 248/364] 	* grub-core/commands/verify.c: Save verified
a5bd9f6
 file to avoid it being 	tampered with after verification was done.
a5bd9f6
a5bd9f6
---
a5bd9f6
 ChangeLog                   |  5 +++
a5bd9f6
 grub-core/commands/verify.c | 98 +++++++++++++++++++++++++++++++++++++--------
a5bd9f6
 include/grub/misc.h         |  2 +
a5bd9f6
 3 files changed, 88 insertions(+), 17 deletions(-)
a5bd9f6
a5bd9f6
diff --git a/ChangeLog b/ChangeLog
a5bd9f6
index b0c57bb..6dc95ba 100644
a5bd9f6
--- a/ChangeLog
a5bd9f6
+++ b/ChangeLog
a5bd9f6
@@ -1,5 +1,10 @@
a5bd9f6
 2013-04-03  Vladimir Serbinenko  <phcoder@gmail.com>
a5bd9f6
 
a5bd9f6
+	* grub-core/commands/verify.c: Save verified file to avoid it being
a5bd9f6
+	tampered with after verification was done.
a5bd9f6
+
a5bd9f6
+2013-04-03  Vladimir Serbinenko  <phcoder@gmail.com>
a5bd9f6
+
a5bd9f6
 	* grub-core/term/i386/pc/console.c (grub_console_getwh): Decrease
a5bd9f6
 	reported width by one to compensate for curesor algorithm problem.
a5bd9f6
 
a5bd9f6
diff --git a/grub-core/commands/verify.c b/grub-core/commands/verify.c
a5bd9f6
index b4d5e7b..bd47611 100644
a5bd9f6
--- a/grub-core/commands/verify.c
a5bd9f6
+++ b/grub-core/commands/verify.c
a5bd9f6
@@ -1,6 +1,6 @@
a5bd9f6
 /*
a5bd9f6
  *  GRUB  --  GRand Unified Bootloader
a5bd9f6
- *  Copyright (C) 2011  Free Software Foundation, Inc.
a5bd9f6
+ *  Copyright (C) 2013  Free Software Foundation, Inc.
a5bd9f6
  *
a5bd9f6
  *  GRUB is free software: you can redistribute it and/or modify
a5bd9f6
  *  it under the terms of the GNU General Public License as published by
a5bd9f6
@@ -338,9 +338,10 @@ grub_crypto_pk_locate_subkey_in_trustdb (grub_uint64_t keyid)
a5bd9f6
   return 0;
a5bd9f6
 }
a5bd9f6
 
a5bd9f6
-grub_err_t
a5bd9f6
-grub_verify_signature (grub_file_t f, grub_file_t sig,
a5bd9f6
-		       struct grub_public_key *pkey)
a5bd9f6
+static grub_err_t
a5bd9f6
+grub_verify_signature_real (char *buf, grub_size_t size,
a5bd9f6
+			    grub_file_t f, grub_file_t sig,
a5bd9f6
+			    struct grub_public_key *pkey)
a5bd9f6
 {
a5bd9f6
   grub_size_t len;
a5bd9f6
   grub_uint8_t v;
a5bd9f6
@@ -404,16 +405,19 @@ grub_verify_signature (grub_file_t f, grub_file_t sig,
a5bd9f6
 
a5bd9f6
     grub_memset (context, 0, sizeof (context));
a5bd9f6
     hash->init (context);
a5bd9f6
-    while (1)
a5bd9f6
-      {
a5bd9f6
-	grub_uint8_t readbuf[4096];
a5bd9f6
-	r = grub_file_read (f, readbuf, sizeof (readbuf));
a5bd9f6
-	if (r < 0)
a5bd9f6
-	  return grub_errno;
a5bd9f6
-	if (r == 0)
a5bd9f6
-	  break;
a5bd9f6
-	hash->write (context, readbuf, r);
a5bd9f6
-      }
a5bd9f6
+    if (buf)
a5bd9f6
+      hash->write (context, buf, size);
a5bd9f6
+    else 
a5bd9f6
+      while (1)
a5bd9f6
+	{
a5bd9f6
+	  grub_uint8_t readbuf[4096];
a5bd9f6
+	  r = grub_file_read (f, readbuf, sizeof (readbuf));
a5bd9f6
+	  if (r < 0)
a5bd9f6
+	    return grub_errno;
a5bd9f6
+	  if (r == 0)
a5bd9f6
+	    break;
a5bd9f6
+	  hash->write (context, readbuf, r);
a5bd9f6
+	}
a5bd9f6
 
a5bd9f6
     hash->write (context, &v, sizeof (v));
a5bd9f6
     hash->write (context, &v4, sizeof (v4));
a5bd9f6
@@ -532,6 +536,13 @@ grub_verify_signature (grub_file_t f, grub_file_t sig,
a5bd9f6
   return GRUB_ERR_NONE;
a5bd9f6
 }
a5bd9f6
 
a5bd9f6
+grub_err_t
a5bd9f6
+grub_verify_signature (grub_file_t f, grub_file_t sig,
a5bd9f6
+		       struct grub_public_key *pkey)
a5bd9f6
+{
a5bd9f6
+  return grub_verify_signature_real (0, 0, f, sig, pkey);
a5bd9f6
+}
a5bd9f6
+
a5bd9f6
 static grub_err_t
a5bd9f6
 grub_cmd_trust (grub_command_t cmd  __attribute__ ((unused)),
a5bd9f6
 			   int argc, char **args)
a5bd9f6
@@ -665,6 +676,28 @@ grub_cmd_verify_signature (grub_command_t cmd  __attribute__ ((unused)),
a5bd9f6
 
a5bd9f6
 static int sec = 0;
a5bd9f6
 
a5bd9f6
+static grub_ssize_t
a5bd9f6
+verified_read (struct grub_file *file, char *buf, grub_size_t len)
a5bd9f6
+{
a5bd9f6
+  grub_memcpy (buf, (char *) file->data + file->offset, len);
a5bd9f6
+  return len;
a5bd9f6
+}
a5bd9f6
+
a5bd9f6
+static grub_err_t
a5bd9f6
+verified_close (struct grub_file *file)
a5bd9f6
+{
a5bd9f6
+  grub_free (file->data);
a5bd9f6
+  file->data = 0;
a5bd9f6
+  return GRUB_ERR_NONE;
a5bd9f6
+}
a5bd9f6
+
a5bd9f6
+struct grub_fs verified_fs =
a5bd9f6
+{
a5bd9f6
+  .name = "verified_read",
a5bd9f6
+  .read = verified_read,
a5bd9f6
+  .close = verified_close
a5bd9f6
+};
a5bd9f6
+
a5bd9f6
 static grub_file_t
a5bd9f6
 grub_pubkey_open (grub_file_t io, const char *filename)
a5bd9f6
 {
a5bd9f6
@@ -672,9 +705,12 @@ grub_pubkey_open (grub_file_t io, const char *filename)
a5bd9f6
   char *fsuf, *ptr;
a5bd9f6
   grub_err_t err;
a5bd9f6
   grub_file_filter_t curfilt[GRUB_FILE_FILTER_MAX];
a5bd9f6
+  grub_file_t ret;
a5bd9f6
 
a5bd9f6
   if (!sec)
a5bd9f6
     return io;
a5bd9f6
+  if (io->device->disk && io->device->disk->id == GRUB_DISK_DEVICE_MEMDISK_ID)
a5bd9f6
+    return io;
a5bd9f6
   fsuf = grub_malloc (grub_strlen (filename) + sizeof (".sig"));
a5bd9f6
   if (!fsuf)
a5bd9f6
     return NULL;
a5bd9f6
@@ -691,12 +727,40 @@ grub_pubkey_open (grub_file_t io, const char *filename)
a5bd9f6
   if (!sig)
a5bd9f6
     return NULL;
a5bd9f6
 
a5bd9f6
-  err = grub_verify_signature (io, sig, NULL);
a5bd9f6
+  ret = grub_malloc (sizeof (*ret));
a5bd9f6
+  if (!ret)
a5bd9f6
+    return NULL;
a5bd9f6
+  *ret = *io;
a5bd9f6
+
a5bd9f6
+  ret->fs = &verified_fs;
a5bd9f6
+  ret->not_easily_seekable = 0;
a5bd9f6
+  if (ret->size >> (sizeof (grub_size_t) * GRUB_CHAR_BIT - 1))
a5bd9f6
+    {
a5bd9f6
+      grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
a5bd9f6
+		  "big file signature isn't implemented yet");
a5bd9f6
+      return NULL;
a5bd9f6
+    }
a5bd9f6
+  ret->data = grub_malloc (ret->size);
a5bd9f6
+  if (!ret->data)
a5bd9f6
+    {
a5bd9f6
+      grub_free (ret);
a5bd9f6
+      return NULL;
a5bd9f6
+    }
a5bd9f6
+  if (grub_file_read (io, ret->data, ret->size) != (grub_ssize_t) ret->size)
a5bd9f6
+    {
a5bd9f6
+      if (!grub_errno)
a5bd9f6
+	grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
a5bd9f6
+		    filename);
a5bd9f6
+      return NULL;
a5bd9f6
+    }
a5bd9f6
+
a5bd9f6
+  err = grub_verify_signature_real (ret->data, ret->size, 0, sig, NULL);
a5bd9f6
   grub_file_close (sig);
a5bd9f6
   if (err)
a5bd9f6
     return NULL;
a5bd9f6
-  grub_file_seek (io, 0);
a5bd9f6
-  return io;
a5bd9f6
+  io->device = 0;
a5bd9f6
+  grub_file_close (io);
a5bd9f6
+  return ret;
a5bd9f6
 }
a5bd9f6
 
a5bd9f6
 static char *
a5bd9f6
diff --git a/include/grub/misc.h b/include/grub/misc.h
a5bd9f6
index c953a00..0ea5114 100644
a5bd9f6
--- a/include/grub/misc.h
a5bd9f6
+++ b/include/grub/misc.h
a5bd9f6
@@ -481,4 +481,6 @@ void EXPORT_FUNC(grub_real_boot_time) (const char *file,
a5bd9f6
 #define grub_max(a, b) (((a) > (b)) ? (a) : (b))
a5bd9f6
 #define grub_min(a, b) (((a) < (b)) ? (a) : (b))
a5bd9f6
 
a5bd9f6
+#define GRUB_CHAR_BIT 8
a5bd9f6
+
a5bd9f6
 #endif /* ! GRUB_MISC_HEADER */
a5bd9f6
-- 
a5bd9f6
1.8.1.4
a5bd9f6