modules: don't hand 0 to vmalloc.
In commitd0a21265dfDavid Rientjes unified various archs' module_alloc implementation (including x86) and removed the graduitous shortcut for size == 0. Then, in commitde7d2b567d, Joe Perches added a warning for zero-length vmallocs, which can happen without kallsyms on modules with no init sections (eg. zlib_deflate). Fix this once and for all; the module code has to handle zero length anyway, so get it right at the caller and remove the now-gratuitous checks within the arch-specific module_alloc implementations. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=42608 Reported-by: Conrad Kostecki <ConiKost@gmx.de> Cc: David Rientjes <rientjes@google.com> Cc: Joe Perches <joe@perches.com> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
		
					parent
					
						
							
								54523ec71f
							
						
					
				
			
			
				commit
				
					
						82fab442f5
					
				
			
		
					 6 changed files with 18 additions and 28 deletions
				
			
		| 
						 | 
					@ -32,8 +32,6 @@
 | 
				
			||||||
#ifdef CONFIG_ETRAX_KMALLOCED_MODULES
 | 
					#ifdef CONFIG_ETRAX_KMALLOCED_MODULES
 | 
				
			||||||
void *module_alloc(unsigned long size)
 | 
					void *module_alloc(unsigned long size)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (size == 0)
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
	return kmalloc(size, GFP_KERNEL);
 | 
						return kmalloc(size, GFP_KERNEL);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -214,8 +214,6 @@ static inline int reassemble_22(int as22)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void *module_alloc(unsigned long size)
 | 
					void *module_alloc(unsigned long size)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (size == 0)
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
	/* using RWX means less protection for modules, but it's
 | 
						/* using RWX means less protection for modules, but it's
 | 
				
			||||||
	 * easier than trying to map the text, data, init_text and
 | 
						 * easier than trying to map the text, data, init_text and
 | 
				
			||||||
	 * init_data correctly */
 | 
						 * init_data correctly */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -43,10 +43,6 @@ void *module_alloc(unsigned long size)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	void *ret;
 | 
						void *ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* We handle the zero case fine, unlike vmalloc */
 | 
					 | 
				
			||||||
	if (size == 0)
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = module_map(size);
 | 
						ret = module_map(size);
 | 
				
			||||||
	if (ret)
 | 
						if (ret)
 | 
				
			||||||
		memset(ret, 0, size);
 | 
							memset(ret, 0, size);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -42,8 +42,6 @@ void *module_alloc(unsigned long size)
 | 
				
			||||||
	int i = 0;
 | 
						int i = 0;
 | 
				
			||||||
	int npages;
 | 
						int npages;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (size == 0)
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
	npages = (size + PAGE_SIZE - 1) / PAGE_SIZE;
 | 
						npages = (size + PAGE_SIZE - 1) / PAGE_SIZE;
 | 
				
			||||||
	pages = kmalloc(npages * sizeof(struct page *), GFP_KERNEL);
 | 
						pages = kmalloc(npages * sizeof(struct page *), GFP_KERNEL);
 | 
				
			||||||
	if (pages == NULL)
 | 
						if (pages == NULL)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,9 +27,6 @@ void *module_alloc(unsigned long size)
 | 
				
			||||||
	struct vm_struct *area;
 | 
						struct vm_struct *area;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	size = PAGE_ALIGN(size);
 | 
						size = PAGE_ALIGN(size);
 | 
				
			||||||
	if (!size)
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	area = __get_vm_area(size, VM_ALLOC, MODULES_VADDR, MODULES_END);
 | 
						area = __get_vm_area(size, VM_ALLOC, MODULES_VADDR, MODULES_END);
 | 
				
			||||||
	if (!area)
 | 
						if (!area)
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2377,7 +2377,7 @@ static void dynamic_debug_remove(struct _ddebug *debug)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void * __weak module_alloc(unsigned long size)
 | 
					void * __weak module_alloc(unsigned long size)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return size == 0 ? NULL : vmalloc_exec(size);
 | 
						return vmalloc_exec(size);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void *module_alloc_update_bounds(unsigned long size)
 | 
					static void *module_alloc_update_bounds(unsigned long size)
 | 
				
			||||||
| 
						 | 
					@ -2793,20 +2793,23 @@ static int move_module(struct module *mod, struct load_info *info)
 | 
				
			||||||
	memset(ptr, 0, mod->core_size);
 | 
						memset(ptr, 0, mod->core_size);
 | 
				
			||||||
	mod->module_core = ptr;
 | 
						mod->module_core = ptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ptr = module_alloc_update_bounds(mod->init_size);
 | 
						if (mod->init_size) {
 | 
				
			||||||
	/*
 | 
							ptr = module_alloc_update_bounds(mod->init_size);
 | 
				
			||||||
	 * The pointer to this block is stored in the module structure
 | 
							/*
 | 
				
			||||||
	 * which is inside the block. This block doesn't need to be
 | 
							 * The pointer to this block is stored in the module structure
 | 
				
			||||||
	 * scanned as it contains data and code that will be freed
 | 
							 * which is inside the block. This block doesn't need to be
 | 
				
			||||||
	 * after the module is initialized.
 | 
							 * scanned as it contains data and code that will be freed
 | 
				
			||||||
	 */
 | 
							 * after the module is initialized.
 | 
				
			||||||
	kmemleak_ignore(ptr);
 | 
							 */
 | 
				
			||||||
	if (!ptr && mod->init_size) {
 | 
							kmemleak_ignore(ptr);
 | 
				
			||||||
		module_free(mod, mod->module_core);
 | 
							if (!ptr) {
 | 
				
			||||||
		return -ENOMEM;
 | 
								module_free(mod, mod->module_core);
 | 
				
			||||||
	}
 | 
								return -ENOMEM;
 | 
				
			||||||
	memset(ptr, 0, mod->init_size);
 | 
							}
 | 
				
			||||||
	mod->module_init = ptr;
 | 
							memset(ptr, 0, mod->init_size);
 | 
				
			||||||
 | 
							mod->module_init = ptr;
 | 
				
			||||||
 | 
						} else
 | 
				
			||||||
 | 
							mod->module_init = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Transfer each section which specifies SHF_ALLOC */
 | 
						/* Transfer each section which specifies SHF_ALLOC */
 | 
				
			||||||
	pr_debug("final section addresses:\n");
 | 
						pr_debug("final section addresses:\n");
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue