2018-07-12 14:56:34 +00:00
|
|
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
2018-07-10 19:08:14 +00:00
|
|
|
From: Stefan Fritsch <sf@sfritsch.de>
|
|
|
|
Date: Sun, 1 May 2016 14:32:30 +0200
|
|
|
|
Subject: [PATCH] Implement checksum verification for gunzip
|
|
|
|
|
|
|
|
This implements the crc32 check for the gzip format. Support for zlib's
|
|
|
|
adler checksum is not included, yet.
|
|
|
|
---
|
|
|
|
grub-core/io/gzio.c | 46 +++++++++++++++++++++++++++++++++++++++++-----
|
|
|
|
1 file changed, 41 insertions(+), 5 deletions(-)
|
|
|
|
|
|
|
|
diff --git a/grub-core/io/gzio.c b/grub-core/io/gzio.c
|
|
|
|
index a8e33033bf8..dcf3a870147 100644
|
|
|
|
--- a/grub-core/io/gzio.c
|
|
|
|
+++ b/grub-core/io/gzio.c
|
|
|
|
@@ -43,6 +43,7 @@
|
|
|
|
#include <grub/dl.h>
|
|
|
|
#include <grub/deflate.h>
|
|
|
|
#include <grub/i18n.h>
|
|
|
|
+#include <grub/crypto.h>
|
|
|
|
|
|
|
|
GRUB_MOD_LICENSE ("GPLv3+");
|
|
|
|
|
|
|
|
@@ -94,6 +95,14 @@ struct grub_gzio
|
|
|
|
struct huft *tl;
|
|
|
|
/* The distance code table. */
|
|
|
|
struct huft *td;
|
|
|
|
+ /* The checksum algorithm */
|
|
|
|
+ const gcry_md_spec_t *hdesc;
|
|
|
|
+ /* The wanted checksum */
|
|
|
|
+ grub_uint32_t orig_checksum;
|
|
|
|
+ /* The uncompressed length */
|
|
|
|
+ grub_size_t orig_len;
|
|
|
|
+ /* Context for checksum calculation */
|
|
|
|
+ grub_uint8_t *hcontext;
|
|
|
|
/* The lookup bits for the literal/length code table. */
|
|
|
|
int bl;
|
|
|
|
/* The lookup bits for the distance code table. */
|
|
|
|
@@ -180,7 +189,7 @@ test_gzip_header (grub_file_t file)
|
|
|
|
grub_uint8_t os_type;
|
|
|
|
} hdr;
|
|
|
|
grub_uint16_t extra_len;
|
|
|
|
- grub_uint32_t orig_len;
|
|
|
|
+ grub_uint32_t crc32;
|
|
|
|
grub_gzio_t gzio = file->data;
|
|
|
|
|
|
|
|
if (grub_file_tell (gzio->file) != 0)
|
|
|
|
@@ -215,12 +224,15 @@ test_gzip_header (grub_file_t file)
|
|
|
|
|
|
|
|
/* FIXME: don't do this on not easily seekable files. */
|
|
|
|
{
|
|
|
|
- grub_file_seek (gzio->file, grub_file_size (gzio->file) - 4);
|
|
|
|
- if (grub_file_read (gzio->file, &orig_len, 4) != 4)
|
|
|
|
+ grub_file_seek (gzio->file, grub_file_size (gzio->file) - 8);
|
|
|
|
+ if (grub_file_read (gzio->file, &crc32, 4) != 4)
|
|
|
|
+ return 0;
|
|
|
|
+ gzio->orig_checksum = grub_le_to_cpu32 (crc32);
|
|
|
|
+ if (grub_file_read (gzio->file, &gzio->orig_len, 4) != 4)
|
|
|
|
return 0;
|
|
|
|
/* FIXME: this does not handle files whose original size is over 4GB.
|
|
|
|
But how can we know the real original size? */
|
|
|
|
- file->size = grub_le_to_cpu32 (orig_len);
|
|
|
|
+ file->size = grub_le_to_cpu32 (gzio->orig_len);
|
|
|
|
}
|
|
|
|
|
|
|
|
initialize_tables (gzio);
|
|
|
|
@@ -1095,7 +1107,23 @@ inflate_window (grub_gzio_t gzio)
|
|
|
|
|
|
|
|
gzio->saved_offset += gzio->wp;
|
|
|
|
|
|
|
|
- /* XXX do CRC calculation here! */
|
|
|
|
+ if (gzio->hcontext)
|
|
|
|
+ {
|
|
|
|
+ gzio->hdesc->write (gzio->hcontext, gzio->slide, gzio->wp);
|
|
|
|
+
|
|
|
|
+ if (gzio->saved_offset == gzio->orig_len)
|
|
|
|
+ {
|
|
|
|
+ grub_uint32_t csum;
|
|
|
|
+
|
|
|
|
+ gzio->hdesc->final (gzio->hcontext);
|
|
|
|
+ csum = *(grub_uint32_t *)gzio->hdesc->read (gzio->hcontext);
|
|
|
|
+ csum = grub_be_to_cpu32 (csum);
|
|
|
|
+ if (csum != gzio->orig_checksum)
|
|
|
|
+ grub_error (GRUB_ERR_BAD_COMPRESSED_DATA,
|
|
|
|
+ "checksum mismatch %08x/%08x",
|
|
|
|
+ gzio->orig_checksum, csum);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@@ -1118,6 +1146,9 @@ initialize_tables (grub_gzio_t gzio)
|
|
|
|
huft_free (gzio->td);
|
|
|
|
gzio->tl = NULL;
|
|
|
|
gzio->td = NULL;
|
|
|
|
+
|
|
|
|
+ if (gzio->hcontext)
|
|
|
|
+ gzio->hdesc->init(gzio->hcontext);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@@ -1143,6 +1174,9 @@ grub_gzio_open (grub_file_t io, const char *name __attribute__ ((unused)))
|
|
|
|
|
|
|
|
gzio->file = io;
|
|
|
|
|
|
|
|
+ gzio->hdesc = GRUB_MD_CRC32;
|
|
|
|
+ gzio->hcontext = grub_malloc(gzio->hdesc->contextsize);
|
|
|
|
+
|
|
|
|
file->device = io->device;
|
|
|
|
file->data = gzio;
|
|
|
|
file->fs = &grub_gzio_fs;
|
|
|
|
@@ -1151,6 +1185,7 @@ grub_gzio_open (grub_file_t io, const char *name __attribute__ ((unused)))
|
|
|
|
if (! test_gzip_header (file))
|
|
|
|
{
|
|
|
|
grub_errno = GRUB_ERR_NONE;
|
|
|
|
+ grub_free (gzio->hcontext);
|
|
|
|
grub_free (gzio);
|
|
|
|
grub_free (file);
|
|
|
|
grub_file_seek (io, 0);
|
|
|
|
@@ -1287,6 +1322,7 @@ grub_gzio_close (grub_file_t file)
|
|
|
|
grub_file_close (gzio->file);
|
|
|
|
huft_free (gzio->tl);
|
|
|
|
huft_free (gzio->td);
|
|
|
|
+ grub_free (gzio->hcontext);
|
|
|
|
grub_free (gzio);
|
|
|
|
|
|
|
|
/* No need to close the same device twice. */
|