RE: [PATCH V2 2/3] x86/efi: Fix EFI memory map leaks

2018-12-05 Thread Prakhya, Sai Praneeth
> > -static void __init efi_clean_memmap(void)
> > +void __init efi_clean_memmap(void)
> >   {
> > -   efi_memory_desc_t *out = efi.memmap.map;
> > -   const efi_memory_desc_t *in = out;
> > -   const efi_memory_desc_t *end = efi.memmap.map_end;
> > -   int i, n_removal;
> > -
> > -   for (i = n_removal = 0; in < end; i++) {
> > -   if (efi_memmap_entry_valid(in, i)) {
> > -   if (out != in)
> > -   memcpy(out, in, efi.memmap.desc_size);
> > -   out = (void *)out + efi.memmap.desc_size;
> > -   } else {
> > +   void *out;
> > +   efi_memory_desc_t *md;
> > +   unsigned int i = 0, n_removal = 0;
> 
> Perhaps we can use 'unsigned int i = n_removal = 0;', which appears more
> readable.

Hmm.. that actually throws an compilation error saying that "n_removal is 
undeclared".
So, let's stick with unsigned int i = 0, n_removal = 0;

> 
> > +   struct efi_memory_map new_memmap;
> > +
> > +   for_each_efi_memory_desc(md) {
> > +   if (!efi_memmap_entry_valid(md, i))
> > n_removal++;
> > -   }
> > -   in = (void *)in + efi.memmap.desc_size;
> > }
> >
> > -   if (n_removal > 0) {
> > -   u64 size = efi.memmap.nr_map - n_removal;
> > +   if (n_removal == 0)
> 
> and 'if (!n_removal)' above, to stay in sync with the rest of the code in 
> this file.

Sure! Thanks for the catch. I will fix it.

Regards,
Sai


RE: [PATCH V2 2/3] x86/efi: Fix EFI memory map leaks

2018-12-05 Thread Prakhya, Sai Praneeth
> > if (efi_enabled(EFI_MEMMAP)) {
> > +   /*
> > +* efi_clean_memmap() uses memblock_phys_alloc() to allocate
> > +* memory for new EFI memmap and hence will work only after
> > +* e820__memblock_setup()
> > +*/
> > +   efi_clean_memmap();
> > efi_fake_memmap();
> > efi_find_mirror();
> > efi_esrt_init();
> 
> I'd also suggest a namespace cleanup before we do any material
> modifications:
> 
> 'efi_esrt_init()' is the proper pattern to follow, it's prefixed by efi_, then
> followed by the more generic subsystem (_esrt) and then by the functionality
> (_init). This is a good, hierarchical, top-down nomenclature that makes it 
> easy to
> grep for ESRT functionality by typing 'git grep esrt'.
> 
> The same is not true of the memmap functionality: 'git grep efi_memmap_'
> doesn't do the right thing.
> 
> So I think this should be renamed to:
> 
>   efi_memmap_clean()
>   efi_memmap_insert()
>   efi_memmap_free()
>   efi_memmap_print()
>   efi_memmap_fake()
>   etc.
> 
> While at it, there's another area that could be improved:
> 
>  - efi_memmap_fake() is a bit weird naming: it's not really 'fake',
>presumably the specified table is still very much real, otherwise it
>won't result in a working kernel.
> 
>What that functionality *really* is about is user-defined entries. Why
>not name it in such a fashion? efi_memmap_init_user_defined() or so?

>From the example you gave about efi_esrt_init(), the naming of efi memmap 
related functions does look messy to me now.. and yes, a namespace clean up 
might be good.

Regards,
Sai


Re: [PATCH V2 2/3] x86/efi: Fix EFI memory map leaks

2018-12-05 Thread Bhupesh Sharma
May be the x86 maintainers would have more comments on this, but I have 
a couple of nitpicks. Please see in-line:


On 12/05/2018 06:03 AM, Sai Praneeth Prakhya wrote:

Presently, in efi subsystem of kernel, every time kernel allocates memory
for a new EFI memory map, it forgets to free the memory occupied by the
existing EFI memory map. This could be fixed by unmapping and freeing the
existing EFI memory map every time before installing a new EFI memory map.
Hence, modify efi_memmap_install() accordingly since it's the only place
which installs a new EFI memory map.

Presently, efi_memmap_alloc() allocates only physical memory and every
caller of efi_memmap_alloc() should remap the newly allocated memory in
order to use it. This extra step could sometimes lead to buggy error
handling conditions where in the allocated memory isn't freed should remap
fail. So, push the remap logic into efi_memmap_alloc() so that the error
handling could be improved and it also makes the caller look simpler.

With the modified efi_memmap_alloc() and efi_memmap_install() API's, a
typical flow to install a new EFI memory map would look something like
below.

1. Get the number of entries the new EFI memory map should have (typically
through efi_memmap_split_count()).
2. Allocate memory for the new EFI memory map (efi_memmap_alloc()).
3. Populate memory descriptor entries in the new EFI memory map.
4. Install the new EFI memory map (efi_memmap_install() which also unmaps
and frees existing memory map).

Existing functions like efi_clean_memmap(), efi_arch_mem_reserve(),
efi_free_boot_services() and efi_fake_memmap() are modified to fix the
above mentioned bugs and also to follow the above recommended usage of
API's.

Note that efi_clean_memmap() could be implemented without allocating any
new memory, but since this is not fast path and hence is not a concern for
performance, readability and maintainability wins. So, change it to use
efi_memmap_alloc() and efi_memmap_install().

Signed-off-by: Sai Praneeth Prakhya 
Suggested-by: Ard Biesheuvel 
Cc: Ingo Molnar 
Cc: Borislav Petkov 
Cc: Bhupesh Sharma 
Cc: Ard Biesheuvel 
---
  arch/x86/include/asm/efi.h  |   1 +
  arch/x86/kernel/setup.c |   6 ++
  arch/x86/platform/efi/efi.c |  44 ++--
  arch/x86/platform/efi/quirks.c  |  43 +++-
  drivers/firmware/efi/fake_mem.c |  21 ++
  drivers/firmware/efi/memmap.c   | 118 +++-
  include/linux/efi.h |   7 +-
  7 files changed, 132 insertions(+), 108 deletions(-)

diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
index d1e64ac80b9c..744f945a00e7 100644
--- a/arch/x86/include/asm/efi.h
+++ b/arch/x86/include/asm/efi.h
@@ -143,6 +143,7 @@ extern void efi_switch_mm(struct mm_struct *mm);
  extern void efi_recover_from_page_fault(unsigned long phys_addr);
  extern void efi_free_boot_services(void);
  extern void efi_reserve_boot_services(void);
+extern void __init efi_clean_memmap(void);
  
  struct efi_setup_data {

u64 fw_vendor;
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index b74e7bfed6ab..bed79b238b0d 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -1102,6 +1102,12 @@ void __init setup_arch(char **cmdline_p)
reserve_bios_regions();
  
  	if (efi_enabled(EFI_MEMMAP)) {

+   /*
+* efi_clean_memmap() uses memblock_phys_alloc() to allocate
+* memory for new EFI memmap and hence will work only after
+* e820__memblock_setup()
+*/
+   efi_clean_memmap();
efi_fake_memmap();
efi_find_mirror();
efi_esrt_init();
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index 715601d1c581..63885cc8e34e 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -249,30 +249,36 @@ static bool __init efi_memmap_entry_valid(const 
efi_memory_desc_t *md, int i)
return false;
  }
  
-static void __init efi_clean_memmap(void)

+void __init efi_clean_memmap(void)
  {
-   efi_memory_desc_t *out = efi.memmap.map;
-   const efi_memory_desc_t *in = out;
-   const efi_memory_desc_t *end = efi.memmap.map_end;
-   int i, n_removal;
-
-   for (i = n_removal = 0; in < end; i++) {
-   if (efi_memmap_entry_valid(in, i)) {
-   if (out != in)
-   memcpy(out, in, efi.memmap.desc_size);
-   out = (void *)out + efi.memmap.desc_size;
-   } else {
+   void *out;
+   efi_memory_desc_t *md;
+   unsigned int i = 0, n_removal = 0;


Perhaps we can use 'unsigned int i = n_removal = 0;', which appears more 
readable.



+   struct efi_memory_map new_memmap;
+
+   for_each_efi_memory_desc(md) {
+   if (!efi_memmap_entry_valid(md, i))
n_removal++;
-   }
-   in = 

Re: [PATCH V2 2/3] x86/efi: Fix EFI memory map leaks

2018-12-04 Thread Ingo Molnar


* Sai Praneeth Prakhya  wrote:

>   if (efi_enabled(EFI_MEMMAP)) {
> + /*
> +  * efi_clean_memmap() uses memblock_phys_alloc() to allocate
> +  * memory for new EFI memmap and hence will work only after
> +  * e820__memblock_setup()
> +  */
> + efi_clean_memmap();
>   efi_fake_memmap();
>   efi_find_mirror();
>   efi_esrt_init();

I'd also suggest a namespace cleanup before we do any material 
modifications:

'efi_esrt_init()' is the proper pattern to follow, it's prefixed by efi_, 
then followed by the more generic subsystem (_esrt) and then by the 
functionality (_init). This is a good, hierarchical, top-down 
nomenclature that makes it easy to grep for ESRT functionality by typing 
'git grep esrt'.

The same is not true of the memmap functionality: 'git grep efi_memmap_' 
doesn't do the right thing.

So I think this should be renamed to:

efi_memmap_clean()
efi_memmap_insert()
efi_memmap_free()
efi_memmap_print()
efi_memmap_fake()
etc.

While at it, there's another area that could be improved:

 - efi_memmap_fake() is a bit weird naming: it's not really 'fake', 
   presumably the specified table is still very much real, otherwise it 
   won't result in a working kernel.

   What that functionality *really* is about is user-defined entries. Why 
   not name it in such a fashion? efi_memmap_init_user_defined() or so?

Thanks,

Ingo


[PATCH V2 2/3] x86/efi: Fix EFI memory map leaks

2018-12-04 Thread Sai Praneeth Prakhya
Presently, in efi subsystem of kernel, every time kernel allocates memory
for a new EFI memory map, it forgets to free the memory occupied by the
existing EFI memory map. This could be fixed by unmapping and freeing the
existing EFI memory map every time before installing a new EFI memory map.
Hence, modify efi_memmap_install() accordingly since it's the only place
which installs a new EFI memory map.

Presently, efi_memmap_alloc() allocates only physical memory and every
caller of efi_memmap_alloc() should remap the newly allocated memory in
order to use it. This extra step could sometimes lead to buggy error
handling conditions where in the allocated memory isn't freed should remap
fail. So, push the remap logic into efi_memmap_alloc() so that the error
handling could be improved and it also makes the caller look simpler.

With the modified efi_memmap_alloc() and efi_memmap_install() API's, a
typical flow to install a new EFI memory map would look something like
below.

1. Get the number of entries the new EFI memory map should have (typically
   through efi_memmap_split_count()).
2. Allocate memory for the new EFI memory map (efi_memmap_alloc()).
3. Populate memory descriptor entries in the new EFI memory map.
4. Install the new EFI memory map (efi_memmap_install() which also unmaps
   and frees existing memory map).

Existing functions like efi_clean_memmap(), efi_arch_mem_reserve(),
efi_free_boot_services() and efi_fake_memmap() are modified to fix the
above mentioned bugs and also to follow the above recommended usage of
API's.

Note that efi_clean_memmap() could be implemented without allocating any
new memory, but since this is not fast path and hence is not a concern for
performance, readability and maintainability wins. So, change it to use
efi_memmap_alloc() and efi_memmap_install().

Signed-off-by: Sai Praneeth Prakhya 
Suggested-by: Ard Biesheuvel 
Cc: Ingo Molnar 
Cc: Borislav Petkov 
Cc: Bhupesh Sharma 
Cc: Ard Biesheuvel 
---
 arch/x86/include/asm/efi.h  |   1 +
 arch/x86/kernel/setup.c |   6 ++
 arch/x86/platform/efi/efi.c |  44 ++--
 arch/x86/platform/efi/quirks.c  |  43 +++-
 drivers/firmware/efi/fake_mem.c |  21 ++
 drivers/firmware/efi/memmap.c   | 118 +++-
 include/linux/efi.h |   7 +-
 7 files changed, 132 insertions(+), 108 deletions(-)

diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
index d1e64ac80b9c..744f945a00e7 100644
--- a/arch/x86/include/asm/efi.h
+++ b/arch/x86/include/asm/efi.h
@@ -143,6 +143,7 @@ extern void efi_switch_mm(struct mm_struct *mm);
 extern void efi_recover_from_page_fault(unsigned long phys_addr);
 extern void efi_free_boot_services(void);
 extern void efi_reserve_boot_services(void);
+extern void __init efi_clean_memmap(void);
 
 struct efi_setup_data {
u64 fw_vendor;
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index b74e7bfed6ab..bed79b238b0d 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -1102,6 +1102,12 @@ void __init setup_arch(char **cmdline_p)
reserve_bios_regions();
 
if (efi_enabled(EFI_MEMMAP)) {
+   /*
+* efi_clean_memmap() uses memblock_phys_alloc() to allocate
+* memory for new EFI memmap and hence will work only after
+* e820__memblock_setup()
+*/
+   efi_clean_memmap();
efi_fake_memmap();
efi_find_mirror();
efi_esrt_init();
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index 715601d1c581..63885cc8e34e 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -249,30 +249,36 @@ static bool __init efi_memmap_entry_valid(const 
efi_memory_desc_t *md, int i)
return false;
 }
 
-static void __init efi_clean_memmap(void)
+void __init efi_clean_memmap(void)
 {
-   efi_memory_desc_t *out = efi.memmap.map;
-   const efi_memory_desc_t *in = out;
-   const efi_memory_desc_t *end = efi.memmap.map_end;
-   int i, n_removal;
-
-   for (i = n_removal = 0; in < end; i++) {
-   if (efi_memmap_entry_valid(in, i)) {
-   if (out != in)
-   memcpy(out, in, efi.memmap.desc_size);
-   out = (void *)out + efi.memmap.desc_size;
-   } else {
+   void *out;
+   efi_memory_desc_t *md;
+   unsigned int i = 0, n_removal = 0;
+   struct efi_memory_map new_memmap;
+
+   for_each_efi_memory_desc(md) {
+   if (!efi_memmap_entry_valid(md, i))
n_removal++;
-   }
-   in = (void *)in + efi.memmap.desc_size;
}
 
-   if (n_removal > 0) {
-   u64 size = efi.memmap.nr_map - n_removal;
+   if (n_removal == 0)
+   return;
 
-   pr_warn("Removing %d invalid memory map entries.\n", n_removal);
-