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