Re: [PATCH v2 04/12] mm/execmem, arch: convert remaining overrides of module_alloc to execmem

2023-06-17 Thread Mike Rapoport
On Fri, Jun 16, 2023 at 11:53:54AM -0700, Song Liu wrote:
> On Fri, Jun 16, 2023 at 1:51 AM Mike Rapoport  wrote:
> [...]
> > diff --git a/arch/arm64/kernel/module.c b/arch/arm64/kernel/module.c
> > index 5af4975caeb5..c3d999f3a3dd 100644
> > --- a/arch/arm64/kernel/module.c
> > +++ b/arch/arm64/kernel/module.c
> > @@ -17,56 +17,50 @@
> >  #include 
> >  #include 
> >  #include 
> > +#include 
> >  #include 
> >  #include 
> >  #include 
> >  #include 
> >
> > -void *module_alloc(unsigned long size)
> > +static struct execmem_params execmem_params = {
> > +   .modules = {
> > +   .flags = EXECMEM_KASAN_SHADOW,
> > +   .text = {
> > +   .alignment = MODULE_ALIGN,
> > +   },
> > +   },
> > +};
> > +
> > +struct execmem_params __init *execmem_arch_params(void)
> >  {
> > u64 module_alloc_end = module_alloc_base + MODULES_VSIZE;
> > -   gfp_t gfp_mask = GFP_KERNEL;
> > -   void *p;
> > -
> > -   /* Silence the initial allocation */
> > -   if (IS_ENABLED(CONFIG_ARM64_MODULE_PLTS))
> > -   gfp_mask |= __GFP_NOWARN;
> >
> > -   if (IS_ENABLED(CONFIG_KASAN_GENERIC) ||
> > -   IS_ENABLED(CONFIG_KASAN_SW_TAGS))
> > -   /* don't exceed the static module region - see below */
> > -   module_alloc_end = MODULES_END;
> > +   execmem_params.modules.text.pgprot = PAGE_KERNEL;
> > +   execmem_params.modules.text.start = module_alloc_base;
> 
> I think I mentioned this earlier. For arm64 with CONFIG_RANDOMIZE_BASE,
> module_alloc_base is not yet set when execmem_arch_params() is
> called. So we will need some extra logic for this.

Right, this is taken care of in a later patch, but it actually belongs here.
Good catch!
 
> Thanks,
> Song
> 
> 
> > +   execmem_params.modules.text.end = module_alloc_end;
> >
> > -   p = __vmalloc_node_range(size, MODULE_ALIGN, module_alloc_base,
> > -   module_alloc_end, gfp_mask, PAGE_KERNEL, 
> > VM_DEFER_KMEMLEAK,
> > -   NUMA_NO_NODE, __builtin_return_address(0));
> > -
> > -   if (!p && IS_ENABLED(CONFIG_ARM64_MODULE_PLTS) &&
> > +   /*
> > +* KASAN without KASAN_VMALLOC can only deal with module
> > +* allocations being served from the reserved module region,
> > +* since the remainder of the vmalloc region is already
> > +* backed by zero shadow pages, and punching holes into it
> > +* is non-trivial. Since the module region is not randomized
> > +* when KASAN is enabled without KASAN_VMALLOC, it is even
> > +* less likely that the module region gets exhausted, so we
> > +* can simply omit this fallback in that case.
> > +*/
> > +   if (IS_ENABLED(CONFIG_ARM64_MODULE_PLTS) &&
> > (IS_ENABLED(CONFIG_KASAN_VMALLOC) ||
> >  (!IS_ENABLED(CONFIG_KASAN_GENERIC) &&
> > - !IS_ENABLED(CONFIG_KASAN_SW_TAGS
> > -   /*
> > -* KASAN without KASAN_VMALLOC can only deal with module
> > -* allocations being served from the reserved module region,
> > -* since the remainder of the vmalloc region is already
> > -* backed by zero shadow pages, and punching holes into it
> > -* is non-trivial. Since the module region is not randomized
> > -* when KASAN is enabled without KASAN_VMALLOC, it is even
> > -* less likely that the module region gets exhausted, so we
> > -* can simply omit this fallback in that case.
> > -*/
> > -   p = __vmalloc_node_range(size, MODULE_ALIGN, 
> > module_alloc_base,
> > -   module_alloc_base + SZ_2G, GFP_KERNEL,
> > -   PAGE_KERNEL, 0, NUMA_NO_NODE,
> > -   __builtin_return_address(0));
> > -
> > -   if (p && (kasan_alloc_module_shadow(p, size, gfp_mask) < 0)) {
> > -   vfree(p);
> > -   return NULL;
> > + !IS_ENABLED(CONFIG_KASAN_SW_TAGS {
> > +   unsigned long end = module_alloc_base + SZ_2G;
> > +
> > +   execmem_params.modules.text.fallback_start = 
> > module_alloc_base;
> > +   execmem_params.modules.text.fallback_end = end;
> > }
> >
> > -   /* Memory is intended to be executable, reset the pointer tag. */
> > -   return kasan_reset_tag(p);
> > +   return _params;
> >  }
> >
> >  enum aarch64_reloc_op {

-- 
Sincerely yours,
Mike.


Re: [PATCH v2 04/12] mm/execmem, arch: convert remaining overrides of module_alloc to execmem

2023-06-17 Thread Mike Rapoport
On Fri, Jun 16, 2023 at 04:16:28PM +, Edgecombe, Rick P wrote:
> On Fri, 2023-06-16 at 11:50 +0300, Mike Rapoport wrote:
> > -void *module_alloc(unsigned long size)
> > -{
> > -   gfp_t gfp_mask = GFP_KERNEL;
> > -   void *p;
> > -
> > -   if (PAGE_ALIGN(size) > MODULES_LEN)
> > -   return NULL;
> > +static struct execmem_params execmem_params = {
> > +   .modules = {
> > +   .flags = EXECMEM_KASAN_SHADOW,
> > +   .text = {
> > +   .alignment = MODULE_ALIGN,
> > +   },
> > +   },
> > +};
> 
> Did you consider making these execmem_params's ro_after_init? Not that
> it is security sensitive, but it's a nice hint to the reader that it is
> only modified at init. And I guess basically free sanitizing of buggy
> writes to it.

Makes sense.
 
> >  
> > -   p = __vmalloc_node_range(size, MODULE_ALIGN,
> > -    MODULES_VADDR +
> > get_module_load_offset(),
> > -    MODULES_END, gfp_mask, PAGE_KERNEL,
> > -    VM_FLUSH_RESET_PERMS |
> > VM_DEFER_KMEMLEAK,
> > -    NUMA_NO_NODE,
> > __builtin_return_address(0));
> > +struct execmem_params __init *execmem_arch_params(void)
> > +{
> > +   unsigned long start = MODULES_VADDR +
> > get_module_load_offset();
> 
> I think we can drop the mutex's in get_module_load_offset() now, since
> execmem_arch_params() should only be called once at init.

Right. Even more, the entire get_module_load_offset() can be folded into
execmem_arch_params() as 

if (IS_ENABLED(CONFIG_RANDOMIZE_BASE) && kaslr_enabled())
module_load_offset =
get_random_u32_inclusive(1, 1024) * PAGE_SIZE;

> >  
> > -   if (p && (kasan_alloc_module_shadow(p, size, gfp_mask) < 0))
> > {
> > -   vfree(p);
> > -   return NULL;
> > -   }
> > +   execmem_params.modules.text.start = start;
> > +   execmem_params.modules.text.end = MODULES_END;
> > +   execmem_params.modules.text.pgprot = PAGE_KERNEL;
> >  
> > -   return p;
> > +   return _params;
> >  }
> >  
> 

-- 
Sincerely yours,
Mike.


Re: [PATCH v2 04/12] mm/execmem, arch: convert remaining overrides of module_alloc to execmem

2023-06-16 Thread Song Liu
On Fri, Jun 16, 2023 at 1:51 AM Mike Rapoport  wrote:
[...]
> diff --git a/arch/arm64/kernel/module.c b/arch/arm64/kernel/module.c
> index 5af4975caeb5..c3d999f3a3dd 100644
> --- a/arch/arm64/kernel/module.c
> +++ b/arch/arm64/kernel/module.c
> @@ -17,56 +17,50 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  #include 
>  #include 
>  #include 
>  #include 
>
> -void *module_alloc(unsigned long size)
> +static struct execmem_params execmem_params = {
> +   .modules = {
> +   .flags = EXECMEM_KASAN_SHADOW,
> +   .text = {
> +   .alignment = MODULE_ALIGN,
> +   },
> +   },
> +};
> +
> +struct execmem_params __init *execmem_arch_params(void)
>  {
> u64 module_alloc_end = module_alloc_base + MODULES_VSIZE;
> -   gfp_t gfp_mask = GFP_KERNEL;
> -   void *p;
> -
> -   /* Silence the initial allocation */
> -   if (IS_ENABLED(CONFIG_ARM64_MODULE_PLTS))
> -   gfp_mask |= __GFP_NOWARN;
>
> -   if (IS_ENABLED(CONFIG_KASAN_GENERIC) ||
> -   IS_ENABLED(CONFIG_KASAN_SW_TAGS))
> -   /* don't exceed the static module region - see below */
> -   module_alloc_end = MODULES_END;
> +   execmem_params.modules.text.pgprot = PAGE_KERNEL;
> +   execmem_params.modules.text.start = module_alloc_base;

I think I mentioned this earlier. For arm64 with CONFIG_RANDOMIZE_BASE,
module_alloc_base is not yet set when execmem_arch_params() is
called. So we will need some extra logic for this.

Thanks,
Song


> +   execmem_params.modules.text.end = module_alloc_end;
>
> -   p = __vmalloc_node_range(size, MODULE_ALIGN, module_alloc_base,
> -   module_alloc_end, gfp_mask, PAGE_KERNEL, 
> VM_DEFER_KMEMLEAK,
> -   NUMA_NO_NODE, __builtin_return_address(0));
> -
> -   if (!p && IS_ENABLED(CONFIG_ARM64_MODULE_PLTS) &&
> +   /*
> +* KASAN without KASAN_VMALLOC can only deal with module
> +* allocations being served from the reserved module region,
> +* since the remainder of the vmalloc region is already
> +* backed by zero shadow pages, and punching holes into it
> +* is non-trivial. Since the module region is not randomized
> +* when KASAN is enabled without KASAN_VMALLOC, it is even
> +* less likely that the module region gets exhausted, so we
> +* can simply omit this fallback in that case.
> +*/
> +   if (IS_ENABLED(CONFIG_ARM64_MODULE_PLTS) &&
> (IS_ENABLED(CONFIG_KASAN_VMALLOC) ||
>  (!IS_ENABLED(CONFIG_KASAN_GENERIC) &&
> - !IS_ENABLED(CONFIG_KASAN_SW_TAGS
> -   /*
> -* KASAN without KASAN_VMALLOC can only deal with module
> -* allocations being served from the reserved module region,
> -* since the remainder of the vmalloc region is already
> -* backed by zero shadow pages, and punching holes into it
> -* is non-trivial. Since the module region is not randomized
> -* when KASAN is enabled without KASAN_VMALLOC, it is even
> -* less likely that the module region gets exhausted, so we
> -* can simply omit this fallback in that case.
> -*/
> -   p = __vmalloc_node_range(size, MODULE_ALIGN, 
> module_alloc_base,
> -   module_alloc_base + SZ_2G, GFP_KERNEL,
> -   PAGE_KERNEL, 0, NUMA_NO_NODE,
> -   __builtin_return_address(0));
> -
> -   if (p && (kasan_alloc_module_shadow(p, size, gfp_mask) < 0)) {
> -   vfree(p);
> -   return NULL;
> + !IS_ENABLED(CONFIG_KASAN_SW_TAGS {
> +   unsigned long end = module_alloc_base + SZ_2G;
> +
> +   execmem_params.modules.text.fallback_start = 
> module_alloc_base;
> +   execmem_params.modules.text.fallback_end = end;
> }
>
> -   /* Memory is intended to be executable, reset the pointer tag. */
> -   return kasan_reset_tag(p);
> +   return _params;
>  }
>
>  enum aarch64_reloc_op {


Re: [PATCH v2 04/12] mm/execmem, arch: convert remaining overrides of module_alloc to execmem

2023-06-16 Thread Edgecombe, Rick P
On Fri, 2023-06-16 at 11:50 +0300, Mike Rapoport wrote:
> -void *module_alloc(unsigned long size)
> -{
> -   gfp_t gfp_mask = GFP_KERNEL;
> -   void *p;
> -
> -   if (PAGE_ALIGN(size) > MODULES_LEN)
> -   return NULL;
> +static struct execmem_params execmem_params = {
> +   .modules = {
> +   .flags = EXECMEM_KASAN_SHADOW,
> +   .text = {
> +   .alignment = MODULE_ALIGN,
> +   },
> +   },
> +};

Did you consider making these execmem_params's ro_after_init? Not that
it is security sensitive, but it's a nice hint to the reader that it is
only modified at init. And I guess basically free sanitizing of buggy
writes to it.

>  
> -   p = __vmalloc_node_range(size, MODULE_ALIGN,
> -    MODULES_VADDR +
> get_module_load_offset(),
> -    MODULES_END, gfp_mask, PAGE_KERNEL,
> -    VM_FLUSH_RESET_PERMS |
> VM_DEFER_KMEMLEAK,
> -    NUMA_NO_NODE,
> __builtin_return_address(0));
> +struct execmem_params __init *execmem_arch_params(void)
> +{
> +   unsigned long start = MODULES_VADDR +
> get_module_load_offset();

I think we can drop the mutex's in get_module_load_offset() now, since
execmem_arch_params() should only be called once at init.

>  
> -   if (p && (kasan_alloc_module_shadow(p, size, gfp_mask) < 0))
> {
> -   vfree(p);
> -   return NULL;
> -   }
> +   execmem_params.modules.text.start = start;
> +   execmem_params.modules.text.end = MODULES_END;
> +   execmem_params.modules.text.pgprot = PAGE_KERNEL;
>  
> -   return p;
> +   return _params;
>  }
>