diff options
| -rw-r--r-- | include/linux/security.h | 13 | ||||
| -rw-r--r-- | kernel/module.c | 11 | ||||
| -rw-r--r-- | security/capability.c | 6 | ||||
| -rw-r--r-- | security/security.c | 5 | 
4 files changed, 35 insertions, 0 deletions
diff --git a/include/linux/security.h b/include/linux/security.h index 05e88bdcf7d..0f6afc657f7 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -694,6 +694,12 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)   *	userspace to load a kernel module with the given name.   *	@kmod_name name of the module requested by the kernel   *	Return 0 if successful. + * @kernel_module_from_file: + *	Load a kernel module from userspace. + *	@file contains the file structure pointing to the file containing + *	the kernel module to load. If the module is being loaded from a blob, + *	this argument will be NULL. + *	Return 0 if permission is granted.   * @task_fix_setuid:   *	Update the module's state after setting one or more of the user   *	identity attributes of the current process.  The @flags parameter @@ -1508,6 +1514,7 @@ struct security_operations {  	int (*kernel_act_as)(struct cred *new, u32 secid);  	int (*kernel_create_files_as)(struct cred *new, struct inode *inode);  	int (*kernel_module_request)(char *kmod_name); +	int (*kernel_module_from_file)(struct file *file);  	int (*task_fix_setuid) (struct cred *new, const struct cred *old,  				int flags);  	int (*task_setpgid) (struct task_struct *p, pid_t pgid); @@ -1765,6 +1772,7 @@ void security_transfer_creds(struct cred *new, const struct cred *old);  int security_kernel_act_as(struct cred *new, u32 secid);  int security_kernel_create_files_as(struct cred *new, struct inode *inode);  int security_kernel_module_request(char *kmod_name); +int security_kernel_module_from_file(struct file *file);  int security_task_fix_setuid(struct cred *new, const struct cred *old,  			     int flags);  int security_task_setpgid(struct task_struct *p, pid_t pgid); @@ -2278,6 +2286,11 @@ static inline int security_kernel_module_request(char *kmod_name)  	return 0;  } +static inline int security_kernel_module_from_file(struct file *file) +{ +	return 0; +} +  static inline int security_task_fix_setuid(struct cred *new,  					   const struct cred *old,  					   int flags) diff --git a/kernel/module.c b/kernel/module.c index 1395ca382fb..a1d2ed8bab9 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -29,6 +29,7 @@  #include <linux/vmalloc.h>  #include <linux/elf.h>  #include <linux/proc_fs.h> +#include <linux/security.h>  #include <linux/seq_file.h>  #include <linux/syscalls.h>  #include <linux/fcntl.h> @@ -2485,10 +2486,16 @@ static int elf_header_check(struct load_info *info)  static int copy_module_from_user(const void __user *umod, unsigned long len,  				  struct load_info *info)  { +	int err; +  	info->len = len;  	if (info->len < sizeof(*(info->hdr)))  		return -ENOEXEC; +	err = security_kernel_module_from_file(NULL); +	if (err) +		return err; +  	/* Suck in entire file: we'll want most of it. */  	info->hdr = vmalloc(info->len);  	if (!info->hdr) @@ -2515,6 +2522,10 @@ static int copy_module_from_fd(int fd, struct load_info *info)  	if (!file)  		return -ENOEXEC; +	err = security_kernel_module_from_file(file); +	if (err) +		goto out; +  	err = vfs_getattr(file->f_vfsmnt, file->f_dentry, &stat);  	if (err)  		goto out; diff --git a/security/capability.c b/security/capability.c index b14a30c234b..0fe5a026aef 100644 --- a/security/capability.c +++ b/security/capability.c @@ -395,6 +395,11 @@ static int cap_kernel_module_request(char *kmod_name)  	return 0;  } +static int cap_kernel_module_from_file(struct file *file) +{ +	return 0; +} +  static int cap_task_setpgid(struct task_struct *p, pid_t pgid)  {  	return 0; @@ -967,6 +972,7 @@ void __init security_fixup_ops(struct security_operations *ops)  	set_to_cap_if_null(ops, kernel_act_as);  	set_to_cap_if_null(ops, kernel_create_files_as);  	set_to_cap_if_null(ops, kernel_module_request); +	set_to_cap_if_null(ops, kernel_module_from_file);  	set_to_cap_if_null(ops, task_fix_setuid);  	set_to_cap_if_null(ops, task_setpgid);  	set_to_cap_if_null(ops, task_getpgid); diff --git a/security/security.c b/security/security.c index 8dcd4ae10a5..ce88630de15 100644 --- a/security/security.c +++ b/security/security.c @@ -820,6 +820,11 @@ int security_kernel_module_request(char *kmod_name)  	return security_ops->kernel_module_request(kmod_name);  } +int security_kernel_module_from_file(struct file *file) +{ +	return security_ops->kernel_module_from_file(file); +} +  int security_task_fix_setuid(struct cred *new, const struct cred *old,  			     int flags)  {  |