]> git.proxmox.com Git - grub2.git/commitdiff
dl: Only allow unloading modules that are not dependencies
authorJavier Martinez Canillas <javierm@redhat.com>
Tue, 29 Sep 2020 12:08:55 +0000 (14:08 +0200)
committerColin Watson <cjwatson@debian.org>
Sat, 27 Feb 2021 14:46:20 +0000 (14:46 +0000)
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>
Patch-Name: 2021-02-security/014-dl-Only-allow-unloading-modules-that-are-not-dependencies.patch

grub-core/commands/minicmd.c
grub-core/kern/dl.c
include/grub/dl.h

index 6bbce3128cf100ae7910163a7622ce3ac650c246..fa498931ed2154ac52ba39d649aa1c88d13fa86c 100644 (file)
@@ -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;
 }
index 074dfc3c6f8e64efc487967c29c4dde86a32eb63..dd0b244614d7c934231fa6da113d311c3b26e011 100644 (file)
@@ -553,6 +553,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)
 {
index f03c03561a154c744f63ba3323775c97be6d8afd..b3753c9ca2628d6c077eaa30ff24ada3b0c1219e 100644 (file)
@@ -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