0028-linux-Fix-integer-overflows-in-initrd-size-handling.patch 5.0 KB

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