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