1*4882a593SmuzhiyunFrom 7630ec5397fe418276b360f9011934b8c034936c Mon Sep 17 00:00:00 2001
2*4882a593SmuzhiyunFrom: Javier Martinez Canillas <javierm@redhat.com>
3*4882a593SmuzhiyunDate: Tue, 29 Sep 2020 14:08:55 +0200
4*4882a593SmuzhiyunSubject: [PATCH] dl: Only allow unloading modules that are not dependencies
5*4882a593Smuzhiyun
6*4882a593SmuzhiyunWhen a module is attempted to be removed its reference counter is always
7*4882a593Smuzhiyundecremented. This means that repeated rmmod invocations will cause the
8*4882a593Smuzhiyunmodule to be unloaded even if another module depends on it.
9*4882a593Smuzhiyun
10*4882a593SmuzhiyunThis may lead to a use-after-free scenario allowing an attacker to execute
11*4882a593Smuzhiyunarbitrary code and by-pass the UEFI Secure Boot protection.
12*4882a593Smuzhiyun
13*4882a593SmuzhiyunWhile being there, add the extern keyword to some function declarations in
14*4882a593Smuzhiyunthat header file.
15*4882a593Smuzhiyun
16*4882a593SmuzhiyunFixes: CVE-2020-25632
17*4882a593Smuzhiyun
18*4882a593SmuzhiyunReported-by: Chris Coulson <chris.coulson@canonical.com>
19*4882a593SmuzhiyunSigned-off-by: Javier Martinez Canillas <javierm@redhat.com>
20*4882a593SmuzhiyunReviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
21*4882a593SmuzhiyunSigned-off-by: Stefan Sørensen <stefan.sorensen@spectralink.com>
22*4882a593Smuzhiyun---
23*4882a593Smuzhiyun grub-core/commands/minicmd.c | 7 +++++--
24*4882a593Smuzhiyun grub-core/kern/dl.c          | 9 +++++++++
25*4882a593Smuzhiyun include/grub/dl.h            | 8 +++++---
26*4882a593Smuzhiyun 3 files changed, 19 insertions(+), 5 deletions(-)
27*4882a593Smuzhiyun
28*4882a593Smuzhiyundiff --git a/grub-core/commands/minicmd.c b/grub-core/commands/minicmd.c
29*4882a593Smuzhiyunindex 6bbce31..fa49893 100644
30*4882a593Smuzhiyun--- a/grub-core/commands/minicmd.c
31*4882a593Smuzhiyun+++ b/grub-core/commands/minicmd.c
32*4882a593Smuzhiyun@@ -140,8 +140,11 @@ grub_mini_cmd_rmmod (struct grub_command *cmd __attribute__ ((unused)),
33*4882a593Smuzhiyun   if (grub_dl_is_persistent (mod))
34*4882a593Smuzhiyun     return grub_error (GRUB_ERR_BAD_ARGUMENT, "cannot unload persistent module");
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun-  if (grub_dl_unref (mod) <= 0)
37*4882a593Smuzhiyun-    grub_dl_unload (mod);
38*4882a593Smuzhiyun+  if (grub_dl_ref_count (mod) > 1)
39*4882a593Smuzhiyun+    return grub_error (GRUB_ERR_BAD_ARGUMENT, "cannot unload referenced module");
40*4882a593Smuzhiyun+
41*4882a593Smuzhiyun+  grub_dl_unref (mod);
42*4882a593Smuzhiyun+  grub_dl_unload (mod);
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun   return 0;
45*4882a593Smuzhiyun }
46*4882a593Smuzhiyundiff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
47*4882a593Smuzhiyunindex 48eb5e7..48f8a79 100644
48*4882a593Smuzhiyun--- a/grub-core/kern/dl.c
49*4882a593Smuzhiyun+++ b/grub-core/kern/dl.c
50*4882a593Smuzhiyun@@ -549,6 +549,15 @@ grub_dl_unref (grub_dl_t mod)
51*4882a593Smuzhiyun   return --mod->ref_count;
52*4882a593Smuzhiyun }
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun+int
55*4882a593Smuzhiyun+grub_dl_ref_count (grub_dl_t mod)
56*4882a593Smuzhiyun+{
57*4882a593Smuzhiyun+  if (mod == NULL)
58*4882a593Smuzhiyun+    return 0;
59*4882a593Smuzhiyun+
60*4882a593Smuzhiyun+  return mod->ref_count;
61*4882a593Smuzhiyun+}
62*4882a593Smuzhiyun+
63*4882a593Smuzhiyun static void
64*4882a593Smuzhiyun grub_dl_flush_cache (grub_dl_t mod)
65*4882a593Smuzhiyun {
66*4882a593Smuzhiyundiff --git a/include/grub/dl.h b/include/grub/dl.h
67*4882a593Smuzhiyunindex f03c035..b3753c9 100644
68*4882a593Smuzhiyun--- a/include/grub/dl.h
69*4882a593Smuzhiyun+++ b/include/grub/dl.h
70*4882a593Smuzhiyun@@ -203,9 +203,11 @@ grub_dl_t EXPORT_FUNC(grub_dl_load) (const char *name);
71*4882a593Smuzhiyun grub_dl_t grub_dl_load_core (void *addr, grub_size_t size);
72*4882a593Smuzhiyun grub_dl_t EXPORT_FUNC(grub_dl_load_core_noinit) (void *addr, grub_size_t size);
73*4882a593Smuzhiyun int EXPORT_FUNC(grub_dl_unload) (grub_dl_t mod);
74*4882a593Smuzhiyun-void grub_dl_unload_unneeded (void);
75*4882a593Smuzhiyun-int EXPORT_FUNC(grub_dl_ref) (grub_dl_t mod);
76*4882a593Smuzhiyun-int EXPORT_FUNC(grub_dl_unref) (grub_dl_t mod);
77*4882a593Smuzhiyun+extern void grub_dl_unload_unneeded (void);
78*4882a593Smuzhiyun+extern int EXPORT_FUNC(grub_dl_ref) (grub_dl_t mod);
79*4882a593Smuzhiyun+extern int EXPORT_FUNC(grub_dl_unref) (grub_dl_t mod);
80*4882a593Smuzhiyun+extern int EXPORT_FUNC(grub_dl_ref_count) (grub_dl_t mod);
81*4882a593Smuzhiyun+
82*4882a593Smuzhiyun extern grub_dl_t EXPORT_VAR(grub_dl_head);
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun #ifndef GRUB_UTIL
85*4882a593Smuzhiyun--
86*4882a593Smuzhiyun2.14.2
87*4882a593Smuzhiyun
88