]> code.ossystems Code Review - openembedded-core.git/blob
d4f9300c0a4da1f0dfede9ab526f1d5fc27d7c22
[openembedded-core.git] /
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