2
1

0004-commands-boot-Add-API-to-pass-context-to-loader.patch 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. From 8b6336696d93b51703c2015eff3e2d8a02145e43 Mon Sep 17 00:00:00 2001
  2. From: Chris Coulson <chris.coulson@canonical.com>
  3. Date: Tue, 5 Apr 2022 10:58:28 +0100
  4. Subject: [PATCH] commands/boot: Add API to pass context to loader
  5. Loaders rely on global variables for saving context which is consumed
  6. in the boot hook and freed in the unload hook. In the case where a loader
  7. command is executed twice, calling grub_loader_set() a second time executes
  8. the unload hook, but in some cases this runs when the loader's global
  9. context has already been updated, resulting in the updated context being
  10. freed and potential use-after-free bugs when the boot hook is subsequently
  11. called.
  12. This adds a new API, grub_loader_set_ex(), which allows a loader to specify
  13. context that is passed to its boot and unload hooks. This is an alternative
  14. to requiring that loaders call grub_loader_unset() before mutating their
  15. global context.
  16. Signed-off-by: Chris Coulson <chris.coulson@canonical.com>
  17. Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
  18. Upstream: 14ceb3b3ff6db664649138442b6562c114dcf56e
  19. [Thomas: needed to backport 04c86e0bb7b58fc2f913f798cdb18934933e532d,
  20. which fixes CVE-2022-28736]
  21. Signed-off-by: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
  22. ---
  23. grub-core/commands/boot.c | 66 ++++++++++++++++++++++++++++++++++-----
  24. include/grub/loader.h | 5 +++
  25. 2 files changed, 63 insertions(+), 8 deletions(-)
  26. diff --git a/grub-core/commands/boot.c b/grub-core/commands/boot.c
  27. index bbca81e94..61514788e 100644
  28. --- a/grub-core/commands/boot.c
  29. +++ b/grub-core/commands/boot.c
  30. @@ -27,10 +27,20 @@
  31. GRUB_MOD_LICENSE ("GPLv3+");
  32. -static grub_err_t (*grub_loader_boot_func) (void);
  33. -static grub_err_t (*grub_loader_unload_func) (void);
  34. +static grub_err_t (*grub_loader_boot_func) (void *context);
  35. +static grub_err_t (*grub_loader_unload_func) (void *context);
  36. +static void *grub_loader_context;
  37. static int grub_loader_flags;
  38. +struct grub_simple_loader_hooks
  39. +{
  40. + grub_err_t (*boot) (void);
  41. + grub_err_t (*unload) (void);
  42. +};
  43. +
  44. +/* Don't heap allocate this to avoid making grub_loader_set() fallible. */
  45. +static struct grub_simple_loader_hooks simple_loader_hooks;
  46. +
  47. struct grub_preboot
  48. {
  49. grub_err_t (*preboot_func) (int);
  50. @@ -44,6 +54,29 @@ static int grub_loader_loaded;
  51. static struct grub_preboot *preboots_head = 0,
  52. *preboots_tail = 0;
  53. +static grub_err_t
  54. +grub_simple_boot_hook (void *context)
  55. +{
  56. + struct grub_simple_loader_hooks *hooks;
  57. +
  58. + hooks = (struct grub_simple_loader_hooks *) context;
  59. + return hooks->boot ();
  60. +}
  61. +
  62. +static grub_err_t
  63. +grub_simple_unload_hook (void *context)
  64. +{
  65. + struct grub_simple_loader_hooks *hooks;
  66. + grub_err_t ret;
  67. +
  68. + hooks = (struct grub_simple_loader_hooks *) context;
  69. +
  70. + ret = hooks->unload ();
  71. + grub_memset (hooks, 0, sizeof (*hooks));
  72. +
  73. + return ret;
  74. +}
  75. +
  76. int
  77. grub_loader_is_loaded (void)
  78. {
  79. @@ -110,28 +143,45 @@ grub_loader_unregister_preboot_hook (struct grub_preboot *hnd)
  80. }
  81. void
  82. -grub_loader_set (grub_err_t (*boot) (void),
  83. - grub_err_t (*unload) (void),
  84. - int flags)
  85. +grub_loader_set_ex (grub_err_t (*boot) (void *context),
  86. + grub_err_t (*unload) (void *context),
  87. + void *context,
  88. + int flags)
  89. {
  90. if (grub_loader_loaded && grub_loader_unload_func)
  91. - grub_loader_unload_func ();
  92. + grub_loader_unload_func (grub_loader_context);
  93. grub_loader_boot_func = boot;
  94. grub_loader_unload_func = unload;
  95. + grub_loader_context = context;
  96. grub_loader_flags = flags;
  97. grub_loader_loaded = 1;
  98. }
  99. +void
  100. +grub_loader_set (grub_err_t (*boot) (void),
  101. + grub_err_t (*unload) (void),
  102. + int flags)
  103. +{
  104. + grub_loader_set_ex (grub_simple_boot_hook,
  105. + grub_simple_unload_hook,
  106. + &simple_loader_hooks,
  107. + flags);
  108. +
  109. + simple_loader_hooks.boot = boot;
  110. + simple_loader_hooks.unload = unload;
  111. +}
  112. +
  113. void
  114. grub_loader_unset(void)
  115. {
  116. if (grub_loader_loaded && grub_loader_unload_func)
  117. - grub_loader_unload_func ();
  118. + grub_loader_unload_func (grub_loader_context);
  119. grub_loader_boot_func = 0;
  120. grub_loader_unload_func = 0;
  121. + grub_loader_context = 0;
  122. grub_loader_loaded = 0;
  123. }
  124. @@ -158,7 +208,7 @@ grub_loader_boot (void)
  125. return err;
  126. }
  127. }
  128. - err = (grub_loader_boot_func) ();
  129. + err = (grub_loader_boot_func) (grub_loader_context);
  130. for (cur = preboots_tail; cur; cur = cur->prev)
  131. if (! err)
  132. diff --git a/include/grub/loader.h b/include/grub/loader.h
  133. index b20864282..97f231054 100644
  134. --- a/include/grub/loader.h
  135. +++ b/include/grub/loader.h
  136. @@ -40,6 +40,11 @@ void EXPORT_FUNC (grub_loader_set) (grub_err_t (*boot) (void),
  137. grub_err_t (*unload) (void),
  138. int flags);
  139. +void EXPORT_FUNC (grub_loader_set_ex) (grub_err_t (*boot) (void *context),
  140. + grub_err_t (*unload) (void *context),
  141. + void *context,
  142. + int flags);
  143. +
  144. /* Unset current loader, if any. */
  145. void EXPORT_FUNC (grub_loader_unset) (void);
  146. --
  147. 2.41.0