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