Blame SOURCES/0385-dl-Only-allow-unloading-modules-that-are-not-depende.patch

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