Blame SOURCES/0330-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
9723a8
index b25ca4b9f17..4660a020bda 100644
9723a8
--- a/grub-core/commands/minicmd.c
9723a8
+++ b/grub-core/commands/minicmd.c
9723a8
@@ -137,8 +137,11 @@ grub_mini_cmd_rmmod (struct grub_command *cmd __attribute__ ((unused)),
9723a8
   if (! mod)
9723a8
     return grub_error (GRUB_ERR_BAD_ARGUMENT, "no such 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
9723a8
index 91105bc4677..333c1329eab 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
9723a8
index 7b5bfb07ce6..a58fbc767c0 100644
9723a8
--- a/include/grub/dl.h
9723a8
+++ b/include/grub/dl.h
9723a8
@@ -204,9 +204,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