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

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