From fec70e69fe9b76fbf7c99ee2c108d548433df13d Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 29 Aug 2012 13:37:10 -0700 Subject: [PATCH] CHROMIUM: security: introduce kernel_module_from_file hook Now that kernel module origins can be reasoned about, provide a hook to the LSMs to make policy decisions about the module file. Signed-off-by: Kees Cook Acked-by: Serge E. Hallyn Acked-by: Eric Paris [accepted into Rusty's modules-wip tree for linux-next: http://git.kernel.org/?p=linux/kernel/git/rusty/linux.git;a=shortlog;h=refs/heads/modules-wip] BUG=chromium-os:34134 TEST=parrot build, manual testing Change-Id: I97f5cc0a0f3c1c04e1dc886d6d20f5a6d82326ac Reviewed-on: https://gerrit.chromium.org/gerrit/34303 Tested-by: Kees Cook Reviewed-by: Olof Johansson Commit-Ready: Kees Cook --- include/linux/security.h | 13 +++++++++++++ kernel/module.c | 9 +++++++++ security/capability.c | 6 ++++++ security/security.c | 5 +++++ 4 files changed, 33 insertions(+) diff --git a/include/linux/security.h b/include/linux/security.h index 00b776196d6..2e4df3d0317 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -695,6 +695,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 @@ -1520,6 +1526,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); @@ -1787,6 +1794,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); @@ -2335,6 +2343,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 d7e1f49d592..c0268d2ae3f 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -2647,6 +2648,10 @@ int copy_module_from_user(const void __user *umod, unsigned long 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) @@ -2685,6 +2690,10 @@ int copy_module_from_fd(int fd, struct load_info *info) if (err) goto out; + err = security_kernel_module_from_file(file); + if (err) + goto out; + size = stat.size; info->hdr = vmalloc(size); if (!info->hdr) { diff --git a/security/capability.c b/security/capability.c index d0a49eeca59..7e2f882a050 100644 --- a/security/capability.c +++ b/security/capability.c @@ -415,6 +415,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; @@ -990,6 +995,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 8b18f4147fe..f60649dc389 100644 --- a/security/security.c +++ b/security/security.c @@ -807,6 +807,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) {