diff options
Diffstat (limited to 'kernel/module.c')
| -rw-r--r-- | kernel/module.c | 53 | 
1 files changed, 34 insertions, 19 deletions
| diff --git a/kernel/module.c b/kernel/module.c index 84a9141a5e15..24dab046e16c 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -337,12 +337,12 @@ static inline void add_taint_module(struct module *mod, unsigned flag,   * A thread that wants to hold a reference to a module only while it   * is running can call this to safely exit.  nfsd and lockd use this.   */ -void __noreturn __module_put_and_exit(struct module *mod, long code) +void __noreturn __module_put_and_kthread_exit(struct module *mod, long code)  {  	module_put(mod); -	do_exit(code); +	kthread_exit(code);  } -EXPORT_SYMBOL(__module_put_and_exit); +EXPORT_SYMBOL(__module_put_and_kthread_exit);  /* Find a module section: 0 means not found. */  static unsigned int find_sec(const struct load_info *info, const char *name) @@ -958,7 +958,6 @@ SYSCALL_DEFINE2(delete_module, const char __user *, name_user,  		}  	} -	/* Stop the machine so refcounts can't move and disable module. */  	ret = try_stop_module(mod, flags, &forced);  	if (ret != 0)  		goto out; @@ -2884,12 +2883,13 @@ static int module_sig_check(struct load_info *info, int flags)  	const unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1;  	const char *reason;  	const void *mod = info->hdr; - +	bool mangled_module = flags & (MODULE_INIT_IGNORE_MODVERSIONS | +				       MODULE_INIT_IGNORE_VERMAGIC);  	/* -	 * Require flags == 0, as a module with version information -	 * removed is no longer the module that was signed +	 * Do not allow mangled modules as a module with version information +	 * removed is no longer the module that was signed.  	 */ -	if (flags == 0 && +	if (!mangled_module &&  	    info->len > markerlen &&  	    memcmp(mod + info->len - markerlen, MODULE_SIG_STRING, markerlen) == 0) {  		/* We truncate the module to discard the signature */ @@ -3174,9 +3174,12 @@ out:  	return err;  } -static void free_copy(struct load_info *info) +static void free_copy(struct load_info *info, int flags)  { -	vfree(info->hdr); +	if (flags & MODULE_INIT_COMPRESSED_FILE) +		module_decompress_cleanup(info); +	else +		vfree(info->hdr);  }  static int rewrite_section_headers(struct load_info *info, int flags) @@ -4125,7 +4128,7 @@ static int load_module(struct load_info *info, const char __user *uargs,  	}  	/* Get rid of temporary copy. */ -	free_copy(info); +	free_copy(info, flags);  	/* Done! */  	trace_module_load(mod); @@ -4174,7 +4177,7 @@ static int load_module(struct load_info *info, const char __user *uargs,  	module_deallocate(mod, info);   free_copy: -	free_copy(info); +	free_copy(info, flags);  	return err;  } @@ -4201,7 +4204,8 @@ SYSCALL_DEFINE3(init_module, void __user *, umod,  SYSCALL_DEFINE3(finit_module, int, fd, const char __user *, uargs, int, flags)  {  	struct load_info info = { }; -	void *hdr = NULL; +	void *buf = NULL; +	int len;  	int err;  	err = may_init_module(); @@ -4211,15 +4215,24 @@ SYSCALL_DEFINE3(finit_module, int, fd, const char __user *, uargs, int, flags)  	pr_debug("finit_module: fd=%d, uargs=%p, flags=%i\n", fd, uargs, flags);  	if (flags & ~(MODULE_INIT_IGNORE_MODVERSIONS -		      |MODULE_INIT_IGNORE_VERMAGIC)) +		      |MODULE_INIT_IGNORE_VERMAGIC +		      |MODULE_INIT_COMPRESSED_FILE))  		return -EINVAL; -	err = kernel_read_file_from_fd(fd, 0, &hdr, INT_MAX, NULL, +	len = kernel_read_file_from_fd(fd, 0, &buf, INT_MAX, NULL,  				       READING_MODULE); -	if (err < 0) -		return err; -	info.hdr = hdr; -	info.len = err; +	if (len < 0) +		return len; + +	if (flags & MODULE_INIT_COMPRESSED_FILE) { +		err = module_decompress(&info, buf, len); +		vfree(buf); /* compressed data is no longer needed */ +		if (err) +			return err; +	} else { +		info.hdr = buf; +		info.len = len; +	}  	return load_module(&info, uargs, flags);  } @@ -4499,6 +4512,8 @@ int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *,  				 mod, kallsyms_symbol_value(sym));  			if (ret != 0)  				goto out; + +			cond_resched();  		}  	}  out: |