1From 0367e7d1b9bac3a78608a672bf6e4ace6a28b964 Mon Sep 17 00:00:00 2001 2From: Colin Watson <cjwatson@debian.org> 3Date: Sat, 25 Jul 2020 12:15:37 +0100 4Subject: [PATCH] linux: Fix integer overflows in initrd size handling 5MIME-Version: 1.0 6Content-Type: text/plain; charset=UTF-8 7Content-Transfer-Encoding: 8bit 8 9These could be triggered by a crafted filesystem with very large files. 10 11Fixes: CVE-2020-15707 12 13Signed-off-by: Colin Watson <cjwatson@debian.org> 14Reviewed-by: Jan Setje-Eilers <jan.setjeeilers@oracle.com> 15Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> 16Signed-off-by: Stefan Sørensen <stefan.sorensen@spectralink.com> 17--- 18 grub-core/loader/linux.c | 74 +++++++++++++++++++++++++++++----------- 19 1 file changed, 54 insertions(+), 20 deletions(-) 20 21diff --git a/grub-core/loader/linux.c b/grub-core/loader/linux.c 22index 4cd8c20c7..3fe390f17 100644 23--- a/grub-core/loader/linux.c 24+++ b/grub-core/loader/linux.c 25@@ -4,6 +4,7 @@ 26 #include <grub/misc.h> 27 #include <grub/file.h> 28 #include <grub/mm.h> 29+#include <grub/safemath.h> 30 31 struct newc_head 32 { 33@@ -98,13 +99,13 @@ free_dir (struct dir *root) 34 grub_free (root); 35 } 36 37-static grub_size_t 38+static grub_err_t 39 insert_dir (const char *name, struct dir **root, 40- grub_uint8_t *ptr) 41+ grub_uint8_t *ptr, grub_size_t *size) 42 { 43 struct dir *cur, **head = root; 44 const char *cb, *ce = name; 45- grub_size_t size = 0; 46+ *size = 0; 47 while (1) 48 { 49 for (cb = ce; *cb == '/'; cb++); 50@@ -130,14 +131,22 @@ insert_dir (const char *name, struct dir **root, 51 ptr = make_header (ptr, name, ce - name, 52 040777, 0); 53 } 54- size += ALIGN_UP ((ce - (char *) name) 55- + sizeof (struct newc_head), 4); 56+ if (grub_add (*size, 57+ ALIGN_UP ((ce - (char *) name) 58+ + sizeof (struct newc_head), 4), 59+ size)) 60+ { 61+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected")); 62+ grub_free (n->name); 63+ grub_free (n); 64+ return grub_errno; 65+ } 66 *head = n; 67 cur = n; 68 } 69 root = &cur->next; 70 } 71- return size; 72+ return GRUB_ERR_NONE; 73 } 74 75 grub_err_t 76@@ -172,26 +181,33 @@ grub_initrd_init (int argc, char *argv[], 77 eptr = grub_strchr (ptr, ':'); 78 if (eptr) 79 { 80+ grub_size_t dir_size, name_len; 81+ 82 initrd_ctx->components[i].newc_name = grub_strndup (ptr, eptr - ptr); 83- if (!initrd_ctx->components[i].newc_name) 84+ if (!initrd_ctx->components[i].newc_name || 85+ insert_dir (initrd_ctx->components[i].newc_name, &root, 0, 86+ &dir_size)) 87 { 88 grub_initrd_close (initrd_ctx); 89 return grub_errno; 90 } 91- initrd_ctx->size 92- += ALIGN_UP (sizeof (struct newc_head) 93- + grub_strlen (initrd_ctx->components[i].newc_name), 94- 4); 95- initrd_ctx->size += insert_dir (initrd_ctx->components[i].newc_name, 96- &root, 0); 97+ name_len = grub_strlen (initrd_ctx->components[i].newc_name); 98+ if (grub_add (initrd_ctx->size, 99+ ALIGN_UP (sizeof (struct newc_head) + name_len, 4), 100+ &initrd_ctx->size) || 101+ grub_add (initrd_ctx->size, dir_size, &initrd_ctx->size)) 102+ goto overflow; 103 newc = 1; 104 fname = eptr + 1; 105 } 106 } 107 else if (newc) 108 { 109- initrd_ctx->size += ALIGN_UP (sizeof (struct newc_head) 110- + sizeof ("TRAILER!!!") - 1, 4); 111+ if (grub_add (initrd_ctx->size, 112+ ALIGN_UP (sizeof (struct newc_head) 113+ + sizeof ("TRAILER!!!") - 1, 4), 114+ &initrd_ctx->size)) 115+ goto overflow; 116 free_dir (root); 117 root = 0; 118 newc = 0; 119@@ -207,19 +223,29 @@ grub_initrd_init (int argc, char *argv[], 120 initrd_ctx->nfiles++; 121 initrd_ctx->components[i].size 122 = grub_file_size (initrd_ctx->components[i].file); 123- initrd_ctx->size += initrd_ctx->components[i].size; 124+ if (grub_add (initrd_ctx->size, initrd_ctx->components[i].size, 125+ &initrd_ctx->size)) 126+ goto overflow; 127 } 128 129 if (newc) 130 { 131 initrd_ctx->size = ALIGN_UP (initrd_ctx->size, 4); 132- initrd_ctx->size += ALIGN_UP (sizeof (struct newc_head) 133- + sizeof ("TRAILER!!!") - 1, 4); 134+ if (grub_add (initrd_ctx->size, 135+ ALIGN_UP (sizeof (struct newc_head) 136+ + sizeof ("TRAILER!!!") - 1, 4), 137+ &initrd_ctx->size)) 138+ goto overflow; 139 free_dir (root); 140 root = 0; 141 } 142 143 return GRUB_ERR_NONE; 144+ 145+ overflow: 146+ free_dir (root); 147+ grub_initrd_close (initrd_ctx); 148+ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected")); 149 } 150 151 grub_size_t 152@@ -260,8 +286,16 @@ grub_initrd_load (struct grub_linux_initrd_context *initrd_ctx, 153 154 if (initrd_ctx->components[i].newc_name) 155 { 156- ptr += insert_dir (initrd_ctx->components[i].newc_name, 157- &root, ptr); 158+ grub_size_t dir_size; 159+ 160+ if (insert_dir (initrd_ctx->components[i].newc_name, &root, ptr, 161+ &dir_size)) 162+ { 163+ free_dir (root); 164+ grub_initrd_close (initrd_ctx); 165+ return grub_errno; 166+ } 167+ ptr += dir_size; 168 ptr = make_header (ptr, initrd_ctx->components[i].newc_name, 169 grub_strlen (initrd_ctx->components[i].newc_name), 170 0100777, 171-- 1722.26.2 173 174