0047-dl-Only-allow-unloading-modules-that-are-not-depende.patch 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. From 7630ec5397fe418276b360f9011934b8c034936c Mon Sep 17 00:00:00 2001
  2. From: Javier Martinez Canillas <javierm@redhat.com>
  3. Date: Tue, 29 Sep 2020 14:08:55 +0200
  4. Subject: [PATCH] dl: Only allow unloading modules that are not dependencies
  5. When a module is attempted to be removed its reference counter is always
  6. decremented. This means that repeated rmmod invocations will cause the
  7. module to be unloaded even if another module depends on it.
  8. This may lead to a use-after-free scenario allowing an attacker to execute
  9. arbitrary code and by-pass the UEFI Secure Boot protection.
  10. While being there, add the extern keyword to some function declarations in
  11. that header file.
  12. Fixes: CVE-2020-25632
  13. Reported-by: Chris Coulson <chris.coulson@canonical.com>
  14. Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
  15. Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
  16. Signed-off-by: Stefan Sørensen <stefan.sorensen@spectralink.com>
  17. ---
  18. grub-core/commands/minicmd.c | 7 +++++--
  19. grub-core/kern/dl.c | 9 +++++++++
  20. include/grub/dl.h | 8 +++++---
  21. 3 files changed, 19 insertions(+), 5 deletions(-)
  22. diff --git a/grub-core/commands/minicmd.c b/grub-core/commands/minicmd.c
  23. index 6bbce31..fa49893 100644
  24. --- a/grub-core/commands/minicmd.c
  25. +++ b/grub-core/commands/minicmd.c
  26. @@ -140,8 +140,11 @@ grub_mini_cmd_rmmod (struct grub_command *cmd __attribute__ ((unused)),
  27. if (grub_dl_is_persistent (mod))
  28. return grub_error (GRUB_ERR_BAD_ARGUMENT, "cannot unload persistent module");
  29. - if (grub_dl_unref (mod) <= 0)
  30. - grub_dl_unload (mod);
  31. + if (grub_dl_ref_count (mod) > 1)
  32. + return grub_error (GRUB_ERR_BAD_ARGUMENT, "cannot unload referenced module");
  33. +
  34. + grub_dl_unref (mod);
  35. + grub_dl_unload (mod);
  36. return 0;
  37. }
  38. diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
  39. index 48eb5e7..48f8a79 100644
  40. --- a/grub-core/kern/dl.c
  41. +++ b/grub-core/kern/dl.c
  42. @@ -549,6 +549,15 @@ grub_dl_unref (grub_dl_t mod)
  43. return --mod->ref_count;
  44. }
  45. +int
  46. +grub_dl_ref_count (grub_dl_t mod)
  47. +{
  48. + if (mod == NULL)
  49. + return 0;
  50. +
  51. + return mod->ref_count;
  52. +}
  53. +
  54. static void
  55. grub_dl_flush_cache (grub_dl_t mod)
  56. {
  57. diff --git a/include/grub/dl.h b/include/grub/dl.h
  58. index f03c035..b3753c9 100644
  59. --- a/include/grub/dl.h
  60. +++ b/include/grub/dl.h
  61. @@ -203,9 +203,11 @@ grub_dl_t EXPORT_FUNC(grub_dl_load) (const char *name);
  62. grub_dl_t grub_dl_load_core (void *addr, grub_size_t size);
  63. grub_dl_t EXPORT_FUNC(grub_dl_load_core_noinit) (void *addr, grub_size_t size);
  64. int EXPORT_FUNC(grub_dl_unload) (grub_dl_t mod);
  65. -void grub_dl_unload_unneeded (void);
  66. -int EXPORT_FUNC(grub_dl_ref) (grub_dl_t mod);
  67. -int EXPORT_FUNC(grub_dl_unref) (grub_dl_t mod);
  68. +extern void grub_dl_unload_unneeded (void);
  69. +extern int EXPORT_FUNC(grub_dl_ref) (grub_dl_t mod);
  70. +extern int EXPORT_FUNC(grub_dl_unref) (grub_dl_t mod);
  71. +extern int EXPORT_FUNC(grub_dl_ref_count) (grub_dl_t mod);
  72. +
  73. extern grub_dl_t EXPORT_VAR(grub_dl_head);
  74. #ifndef GRUB_UTIL
  75. --
  76. 2.14.2