123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687 |
- From 7630ec5397fe418276b360f9011934b8c034936c Mon Sep 17 00:00:00 2001
- From: Javier Martinez Canillas <javierm@redhat.com>
- Date: Tue, 29 Sep 2020 14:08:55 +0200
- Subject: [PATCH] dl: Only allow unloading modules that are not dependencies
- When a module is attempted to be removed its reference counter is always
- decremented. This means that repeated rmmod invocations will cause the
- module to be unloaded even if another module depends on it.
- This may lead to a use-after-free scenario allowing an attacker to execute
- arbitrary code and by-pass the UEFI Secure Boot protection.
- While being there, add the extern keyword to some function declarations in
- that header file.
- Fixes: CVE-2020-25632
- Reported-by: Chris Coulson <chris.coulson@canonical.com>
- Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
- Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
- Signed-off-by: Stefan Sørensen <stefan.sorensen@spectralink.com>
- ---
- grub-core/commands/minicmd.c | 7 +++++--
- grub-core/kern/dl.c | 9 +++++++++
- include/grub/dl.h | 8 +++++---
- 3 files changed, 19 insertions(+), 5 deletions(-)
- diff --git a/grub-core/commands/minicmd.c b/grub-core/commands/minicmd.c
- index 6bbce31..fa49893 100644
- --- a/grub-core/commands/minicmd.c
- +++ b/grub-core/commands/minicmd.c
- @@ -140,8 +140,11 @@ grub_mini_cmd_rmmod (struct grub_command *cmd __attribute__ ((unused)),
- if (grub_dl_is_persistent (mod))
- return grub_error (GRUB_ERR_BAD_ARGUMENT, "cannot unload persistent module");
-
- - if (grub_dl_unref (mod) <= 0)
- - grub_dl_unload (mod);
- + if (grub_dl_ref_count (mod) > 1)
- + return grub_error (GRUB_ERR_BAD_ARGUMENT, "cannot unload referenced module");
- +
- + grub_dl_unref (mod);
- + grub_dl_unload (mod);
-
- return 0;
- }
- diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
- index 48eb5e7..48f8a79 100644
- --- a/grub-core/kern/dl.c
- +++ b/grub-core/kern/dl.c
- @@ -549,6 +549,15 @@ grub_dl_unref (grub_dl_t mod)
- return --mod->ref_count;
- }
-
- +int
- +grub_dl_ref_count (grub_dl_t mod)
- +{
- + if (mod == NULL)
- + return 0;
- +
- + return mod->ref_count;
- +}
- +
- static void
- grub_dl_flush_cache (grub_dl_t mod)
- {
- diff --git a/include/grub/dl.h b/include/grub/dl.h
- index f03c035..b3753c9 100644
- --- a/include/grub/dl.h
- +++ b/include/grub/dl.h
- @@ -203,9 +203,11 @@ grub_dl_t EXPORT_FUNC(grub_dl_load) (const char *name);
- grub_dl_t grub_dl_load_core (void *addr, grub_size_t size);
- grub_dl_t EXPORT_FUNC(grub_dl_load_core_noinit) (void *addr, grub_size_t size);
- int EXPORT_FUNC(grub_dl_unload) (grub_dl_t mod);
- -void grub_dl_unload_unneeded (void);
- -int EXPORT_FUNC(grub_dl_ref) (grub_dl_t mod);
- -int EXPORT_FUNC(grub_dl_unref) (grub_dl_t mod);
- +extern void grub_dl_unload_unneeded (void);
- +extern int EXPORT_FUNC(grub_dl_ref) (grub_dl_t mod);
- +extern int EXPORT_FUNC(grub_dl_unref) (grub_dl_t mod);
- +extern int EXPORT_FUNC(grub_dl_ref_count) (grub_dl_t mod);
- +
- extern grub_dl_t EXPORT_VAR(grub_dl_head);
-
- #ifndef GRUB_UTIL
- --
- 2.14.2
|