From 1e9877902dc7e11d2be038371c6fbf2dfcd469d7 Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Fri, 12 Feb 2016 13:01:54 -0800 Subject: mm/gup: Introduce get_user_pages_remote() For protection keys, we need to understand whether protections should be enforced in software or not. In general, we enforce protections when working on our own task, but not when on others. We call these "current" and "remote" operations. This patch introduces a new get_user_pages() variant: get_user_pages_remote() Which is a replacement for when get_user_pages() is called on non-current tsk/mm. We also introduce a new gup flag: FOLL_REMOTE which can be used for the "__" gup variants to get this new behavior. The uprobes is_trap_at_addr() location holds mmap_sem and calls get_user_pages(current->mm) on an instruction address. This makes it a pretty unique gup caller. Being an instruction access and also really originating from the kernel (vs. the app), I opted to consider this a 'remote' access where protection keys will not be enforced. Without protection keys, this patch should not change any behavior. Signed-off-by: Dave Hansen Reviewed-by: Thomas Gleixner Cc: Andrea Arcangeli Cc: Andrew Morton Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Kirill A. Shutemov Cc: Linus Torvalds Cc: Naoya Horiguchi Cc: Peter Zijlstra Cc: Rik van Riel Cc: Srikar Dronamraju Cc: Vlastimil Babka Cc: jack@suse.cz Cc: linux-mm@kvack.org Link: http://lkml.kernel.org/r/20160212210154.3F0E51EA@viggo.jf.intel.com Signed-off-by: Ingo Molnar --- fs/exec.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'fs/exec.c') diff --git a/fs/exec.c b/fs/exec.c index dcd4ac7d3f1e..d885b98b6a00 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -198,8 +198,12 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos, return NULL; } #endif - ret = get_user_pages(current, bprm->mm, pos, - 1, write, 1, &page, NULL); + /* + * We are doing an exec(). 'current' is the process + * doing the exec and bprm->mm is the new process's mm. + */ + ret = get_user_pages_remote(current, bprm->mm, pos, 1, write, + 1, &page, NULL); if (ret <= 0) return NULL; -- cgit From b44a7dfc6fa16e01f2497c9fa62c3926f94be174 Mon Sep 17 00:00:00 2001 From: Mimi Zohar Date: Mon, 28 Dec 2015 16:02:29 -0500 Subject: vfs: define a generic function to read a file from the kernel For a while it was looked down upon to directly read files from Linux. These days there exists a few mechanisms in the kernel that do just this though to load a file into a local buffer. There are minor but important checks differences on each. This patch set is the first attempt at resolving some of these differences. This patch introduces a common function for reading files from the kernel with the corresponding security post-read hook and function. Changelog v4+: - export security_kernel_post_read_file() - Fengguang Wu v3: - additional bounds checking - Luis v2: - To simplify patch review, re-ordered patches Signed-off-by: Mimi Zohar Reviewed-by: Luis R. Rodriguez Acked-by: Kees Cook Cc: Al Viro --- fs/exec.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++ include/linux/fs.h | 1 + include/linux/lsm_hooks.h | 9 ++++++++ include/linux/security.h | 7 +++++++ security/security.c | 8 +++++++ 5 files changed, 78 insertions(+) (limited to 'fs/exec.c') diff --git a/fs/exec.c b/fs/exec.c index dcd4ac7d3f1e..6b6668baa44a 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -56,6 +56,7 @@ #include #include #include +#include #include #include @@ -831,6 +832,58 @@ int kernel_read(struct file *file, loff_t offset, EXPORT_SYMBOL(kernel_read); +int kernel_read_file(struct file *file, void **buf, loff_t *size, + loff_t max_size) +{ + loff_t i_size, pos; + ssize_t bytes = 0; + int ret; + + if (!S_ISREG(file_inode(file)->i_mode) || max_size < 0) + return -EINVAL; + + i_size = i_size_read(file_inode(file)); + if (max_size > 0 && i_size > max_size) + return -EFBIG; + if (i_size <= 0) + return -EINVAL; + + *buf = vmalloc(i_size); + if (!*buf) + return -ENOMEM; + + pos = 0; + while (pos < i_size) { + bytes = kernel_read(file, pos, (char *)(*buf) + pos, + i_size - pos); + if (bytes < 0) { + ret = bytes; + goto out; + } + + if (bytes == 0) + break; + pos += bytes; + } + + if (pos != i_size) { + ret = -EIO; + goto out; + } + + ret = security_kernel_post_read_file(file, *buf, i_size); + if (!ret) + *size = pos; + +out: + if (ret < 0) { + vfree(*buf); + *buf = NULL; + } + return ret; +} +EXPORT_SYMBOL_GPL(kernel_read_file); + ssize_t read_code(struct file *file, unsigned long addr, loff_t pos, size_t len) { ssize_t res = vfs_read(file, (void __user *)addr, len, &pos); diff --git a/include/linux/fs.h b/include/linux/fs.h index ae681002100a..9a83d82b61ac 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2577,6 +2577,7 @@ static inline void i_readcount_inc(struct inode *inode) extern int do_pipe_flags(int *, int); extern int kernel_read(struct file *, loff_t, char *, unsigned long); +extern int kernel_read_file(struct file *, void **, loff_t *, loff_t); extern ssize_t kernel_write(struct file *, const char *, size_t, loff_t); extern ssize_t __kernel_write(struct file *, const char *, size_t, loff_t *); extern struct file * open_exec(const char *); diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 71969de4058c..f82631cc7248 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -561,6 +561,13 @@ * 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. + * @kernel_post_read_file: + * Read a file specified by userspace. + * @file contains the file structure pointing to the file being read + * by the kernel. + * @buf pointer to buffer containing the file contents. + * @size length of the file contents. + * 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 @@ -1457,6 +1464,7 @@ union security_list_options { int (*kernel_fw_from_file)(struct file *file, char *buf, size_t size); int (*kernel_module_request)(char *kmod_name); int (*kernel_module_from_file)(struct file *file); + int (*kernel_post_read_file)(struct file *file, char *buf, loff_t size); int (*task_fix_setuid)(struct cred *new, const struct cred *old, int flags); int (*task_setpgid)(struct task_struct *p, pid_t pgid); @@ -1716,6 +1724,7 @@ struct security_hook_heads { struct list_head kernel_act_as; struct list_head kernel_create_files_as; struct list_head kernel_fw_from_file; + struct list_head kernel_post_read_file; struct list_head kernel_module_request; struct list_head kernel_module_from_file; struct list_head task_fix_setuid; diff --git a/include/linux/security.h b/include/linux/security.h index 4824a4ccaf1c..f30f5647d1e1 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -301,6 +301,7 @@ int security_kernel_create_files_as(struct cred *new, struct inode *inode); int security_kernel_fw_from_file(struct file *file, char *buf, size_t size); int security_kernel_module_request(char *kmod_name); int security_kernel_module_from_file(struct file *file); +int security_kernel_post_read_file(struct file *file, char *buf, loff_t size); 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); @@ -866,6 +867,12 @@ static inline int security_kernel_module_from_file(struct file *file) return 0; } +static inline int security_kernel_post_read_file(struct file *file, + char *buf, loff_t size) +{ + return 0; +} + static inline int security_task_fix_setuid(struct cred *new, const struct cred *old, int flags) diff --git a/security/security.c b/security/security.c index e8ffd92ae2eb..c98dd6bf4ebd 100644 --- a/security/security.c +++ b/security/security.c @@ -910,6 +910,12 @@ int security_kernel_module_from_file(struct file *file) return ima_module_check(file); } +int security_kernel_post_read_file(struct file *file, char *buf, loff_t size) +{ + return call_int_hook(kernel_post_read_file, 0, file, buf, size); +} +EXPORT_SYMBOL_GPL(security_kernel_post_read_file); + int security_task_fix_setuid(struct cred *new, const struct cred *old, int flags) { @@ -1697,6 +1703,8 @@ struct security_hook_heads security_hook_heads = { LIST_HEAD_INIT(security_hook_heads.kernel_module_request), .kernel_module_from_file = LIST_HEAD_INIT(security_hook_heads.kernel_module_from_file), + .kernel_post_read_file = + LIST_HEAD_INIT(security_hook_heads.kernel_post_read_file), .task_fix_setuid = LIST_HEAD_INIT(security_hook_heads.task_fix_setuid), .task_setpgid = LIST_HEAD_INIT(security_hook_heads.task_setpgid), -- cgit From bc8ca5b92d54f6f005fa73ad546f02fca26ddd85 Mon Sep 17 00:00:00 2001 From: Mimi Zohar Date: Sun, 24 Jan 2016 10:07:32 -0500 Subject: vfs: define kernel_read_file_id enumeration To differentiate between the kernel_read_file() callers, this patch defines a new enumeration named kernel_read_file_id and includes the caller identifier as an argument. Subsequent patches define READING_KEXEC_IMAGE, READING_KEXEC_INITRAMFS, READING_FIRMWARE, READING_MODULE, and READING_POLICY. Changelog v3: - Replace the IMA specific enumeration with a generic one. Signed-off-by: Mimi Zohar Acked-by: Kees Cook Acked-by: Luis R. Rodriguez Cc: Al Viro --- fs/exec.c | 4 ++-- include/linux/fs.h | 7 ++++++- include/linux/lsm_hooks.h | 4 +++- include/linux/security.h | 7 +++++-- security/security.c | 5 +++-- 5 files changed, 19 insertions(+), 8 deletions(-) (limited to 'fs/exec.c') diff --git a/fs/exec.c b/fs/exec.c index 6b6668baa44a..1138dc502c77 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -833,7 +833,7 @@ int kernel_read(struct file *file, loff_t offset, EXPORT_SYMBOL(kernel_read); int kernel_read_file(struct file *file, void **buf, loff_t *size, - loff_t max_size) + loff_t max_size, enum kernel_read_file_id id) { loff_t i_size, pos; ssize_t bytes = 0; @@ -871,7 +871,7 @@ int kernel_read_file(struct file *file, void **buf, loff_t *size, goto out; } - ret = security_kernel_post_read_file(file, *buf, i_size); + ret = security_kernel_post_read_file(file, *buf, i_size, id); if (!ret) *size = pos; diff --git a/include/linux/fs.h b/include/linux/fs.h index 9a83d82b61ac..aa84bcb9c368 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2576,8 +2576,13 @@ static inline void i_readcount_inc(struct inode *inode) #endif extern int do_pipe_flags(int *, int); +enum kernel_read_file_id { + READING_MAX_ID +}; + extern int kernel_read(struct file *, loff_t, char *, unsigned long); -extern int kernel_read_file(struct file *, void **, loff_t *, loff_t); +extern int kernel_read_file(struct file *, void **, loff_t *, loff_t, + enum kernel_read_file_id); extern ssize_t kernel_write(struct file *, const char *, size_t, loff_t); extern ssize_t __kernel_write(struct file *, const char *, size_t, loff_t *); extern struct file * open_exec(const char *); diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index f82631cc7248..2337f33913c1 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -567,6 +567,7 @@ * by the kernel. * @buf pointer to buffer containing the file contents. * @size length of the file contents. + * @id kernel read file identifier * Return 0 if permission is granted. * @task_fix_setuid: * Update the module's state after setting one or more of the user @@ -1464,7 +1465,8 @@ union security_list_options { int (*kernel_fw_from_file)(struct file *file, char *buf, size_t size); int (*kernel_module_request)(char *kmod_name); int (*kernel_module_from_file)(struct file *file); - int (*kernel_post_read_file)(struct file *file, char *buf, loff_t size); + int (*kernel_post_read_file)(struct file *file, char *buf, loff_t size, + enum kernel_read_file_id id); int (*task_fix_setuid)(struct cred *new, const struct cred *old, int flags); int (*task_setpgid)(struct task_struct *p, pid_t pgid); diff --git a/include/linux/security.h b/include/linux/security.h index f30f5647d1e1..b68ce94e4e00 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -28,6 +28,7 @@ #include #include #include +#include struct linux_binprm; struct cred; @@ -301,7 +302,8 @@ int security_kernel_create_files_as(struct cred *new, struct inode *inode); int security_kernel_fw_from_file(struct file *file, char *buf, size_t size); int security_kernel_module_request(char *kmod_name); int security_kernel_module_from_file(struct file *file); -int security_kernel_post_read_file(struct file *file, char *buf, loff_t size); +int security_kernel_post_read_file(struct file *file, char *buf, loff_t size, + enum kernel_read_file_id id); 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); @@ -868,7 +870,8 @@ static inline int security_kernel_module_from_file(struct file *file) } static inline int security_kernel_post_read_file(struct file *file, - char *buf, loff_t size) + char *buf, loff_t size, + enum kernel_read_file_id id) { return 0; } diff --git a/security/security.c b/security/security.c index c98dd6bf4ebd..5b96eabaafd4 100644 --- a/security/security.c +++ b/security/security.c @@ -910,9 +910,10 @@ int security_kernel_module_from_file(struct file *file) return ima_module_check(file); } -int security_kernel_post_read_file(struct file *file, char *buf, loff_t size) +int security_kernel_post_read_file(struct file *file, char *buf, loff_t size, + enum kernel_read_file_id id) { - return call_int_hook(kernel_post_read_file, 0, file, buf, size); + return call_int_hook(kernel_post_read_file, 0, file, buf, size, id); } EXPORT_SYMBOL_GPL(security_kernel_post_read_file); -- cgit From 09596b94f7d28595602482e69ed954deab707437 Mon Sep 17 00:00:00 2001 From: Mimi Zohar Date: Thu, 19 Nov 2015 12:39:22 -0500 Subject: vfs: define kernel_read_file_from_path This patch defines kernel_read_file_from_path(), a wrapper for the VFS common kernel_read_file(). Changelog: - revert error msg regression - reported by Sergey Senozhatsky - Separated from the IMA patch Signed-off-by: Mimi Zohar Acked-by: Kees Cook Acked-by: Luis R. Rodriguez Cc: Al Viro --- fs/exec.c | 19 +++++++++++++++++++ include/linux/fs.h | 2 ++ 2 files changed, 21 insertions(+) (limited to 'fs/exec.c') diff --git a/fs/exec.c b/fs/exec.c index 1138dc502c77..64cb3bc788c1 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -884,6 +884,25 @@ out: } EXPORT_SYMBOL_GPL(kernel_read_file); +int kernel_read_file_from_path(char *path, void **buf, loff_t *size, + loff_t max_size, enum kernel_read_file_id id) +{ + struct file *file; + int ret; + + if (!path || !*path) + return -EINVAL; + + file = filp_open(path, O_RDONLY, 0); + if (IS_ERR(file)) + return PTR_ERR(file); + + ret = kernel_read_file(file, buf, size, max_size, id); + fput(file); + return ret; +} +EXPORT_SYMBOL_GPL(kernel_read_file_from_path); + ssize_t read_code(struct file *file, unsigned long addr, loff_t pos, size_t len) { ssize_t res = vfs_read(file, (void __user *)addr, len, &pos); diff --git a/include/linux/fs.h b/include/linux/fs.h index aa84bcb9c368..00fa5c45fd63 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2583,6 +2583,8 @@ enum kernel_read_file_id { extern int kernel_read(struct file *, loff_t, char *, unsigned long); extern int kernel_read_file(struct file *, void **, loff_t *, loff_t, enum kernel_read_file_id); +extern int kernel_read_file_from_path(char *, void **, loff_t *, loff_t, + enum kernel_read_file_id); extern ssize_t kernel_write(struct file *, const char *, size_t, loff_t); extern ssize_t __kernel_write(struct file *, const char *, size_t, loff_t *); extern struct file * open_exec(const char *); -- cgit From 39eeb4fb97f60dbdfc823c1a673a8844b9226b60 Mon Sep 17 00:00:00 2001 From: Mimi Zohar Date: Sat, 30 Jan 2016 22:23:26 -0500 Subject: security: define kernel_read_file hook The kernel_read_file security hook is called prior to reading the file into memory. Changelog v4+: - export security_kernel_read_file() Signed-off-by: Mimi Zohar Acked-by: Kees Cook Acked-by: Luis R. Rodriguez Acked-by: Casey Schaufler --- fs/exec.c | 4 ++++ include/linux/ima.h | 6 ++++++ include/linux/lsm_hooks.h | 8 ++++++++ include/linux/security.h | 7 +++++++ security/integrity/ima/ima_main.c | 16 ++++++++++++++++ security/security.c | 13 +++++++++++++ 6 files changed, 54 insertions(+) (limited to 'fs/exec.c') diff --git a/fs/exec.c b/fs/exec.c index 64cb3bc788c1..8aaa38666119 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -842,6 +842,10 @@ int kernel_read_file(struct file *file, void **buf, loff_t *size, if (!S_ISREG(file_inode(file)->i_mode) || max_size < 0) return -EINVAL; + ret = security_kernel_read_file(file, id); + if (ret) + return ret; + i_size = i_size_read(file_inode(file)); if (max_size > 0 && i_size > max_size) return -EFBIG; diff --git a/include/linux/ima.h b/include/linux/ima.h index 7aea4863c244..6adcaea8101c 100644 --- a/include/linux/ima.h +++ b/include/linux/ima.h @@ -19,6 +19,7 @@ extern int ima_file_check(struct file *file, int mask, int opened); extern void ima_file_free(struct file *file); extern int ima_file_mmap(struct file *file, unsigned long prot); extern int ima_module_check(struct file *file); +extern int ima_read_file(struct file *file, enum kernel_read_file_id id); extern int ima_post_read_file(struct file *file, void *buf, loff_t size, enum kernel_read_file_id id); @@ -48,6 +49,11 @@ static inline int ima_module_check(struct file *file) return 0; } +static inline int ima_read_file(struct file *file, enum kernel_read_file_id id) +{ + return 0; +} + static inline int ima_post_read_file(struct file *file, void *buf, loff_t size, enum kernel_read_file_id id) { diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 7d04a1220223..d32b7bd13635 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -552,6 +552,12 @@ * 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. + * @kernel_read_file: + * Read a file specified by userspace. + * @file contains the file structure pointing to the file being read + * by the kernel. + * @id kernel read file identifier + * Return 0 if permission is granted. * @kernel_post_read_file: * Read a file specified by userspace. * @file contains the file structure pointing to the file being read @@ -1455,6 +1461,7 @@ union security_list_options { 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 (*kernel_read_file)(struct file *file, enum kernel_read_file_id id); int (*kernel_post_read_file)(struct file *file, char *buf, loff_t size, enum kernel_read_file_id id); int (*task_fix_setuid)(struct cred *new, const struct cred *old, @@ -1715,6 +1722,7 @@ struct security_hook_heads { struct list_head cred_transfer; struct list_head kernel_act_as; struct list_head kernel_create_files_as; + struct list_head kernel_read_file; struct list_head kernel_post_read_file; struct list_head kernel_module_request; struct list_head kernel_module_from_file; diff --git a/include/linux/security.h b/include/linux/security.h index cee1349e1155..071fb747fdbb 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -302,6 +302,7 @@ 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_kernel_read_file(struct file *file, enum kernel_read_file_id id); int security_kernel_post_read_file(struct file *file, char *buf, loff_t size, enum kernel_read_file_id id); int security_task_fix_setuid(struct cred *new, const struct cred *old, @@ -863,6 +864,12 @@ static inline int security_kernel_module_from_file(struct file *file) return 0; } +static inline int security_kernel_read_file(struct file *file, + enum kernel_read_file_id id) +{ + return 0; +} + static inline int security_kernel_post_read_file(struct file *file, char *buf, loff_t size, enum kernel_read_file_id id) diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index e9651be17b72..bbb80df28fb1 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -337,6 +337,22 @@ int ima_module_check(struct file *file) return process_measurement(file, NULL, 0, MAY_EXEC, MODULE_CHECK, 0); } +/** + * ima_read_file - pre-measure/appraise hook decision based on policy + * @file: pointer to the file to be measured/appraised/audit + * @read_id: caller identifier + * + * Permit reading a file based on policy. The policy rules are written + * in terms of the policy identifier. Appraising the integrity of + * a file requires a file descriptor. + * + * For permission return 0, otherwise return -EACCES. + */ +int ima_read_file(struct file *file, enum kernel_read_file_id read_id) +{ + return 0; +} + /** * ima_post_read_file - in memory collect/appraise/audit measurement * @file: pointer to the file to be measured/appraised/audit diff --git a/security/security.c b/security/security.c index cd85be61c416..8e699f98a600 100644 --- a/security/security.c +++ b/security/security.c @@ -899,6 +899,17 @@ int security_kernel_module_from_file(struct file *file) return ima_module_check(file); } +int security_kernel_read_file(struct file *file, enum kernel_read_file_id id) +{ + int ret; + + ret = call_int_hook(kernel_read_file, 0, file, id); + if (ret) + return ret; + return ima_read_file(file, id); +} +EXPORT_SYMBOL_GPL(security_kernel_read_file); + int security_kernel_post_read_file(struct file *file, char *buf, loff_t size, enum kernel_read_file_id id) { @@ -1696,6 +1707,8 @@ struct security_hook_heads security_hook_heads = { LIST_HEAD_INIT(security_hook_heads.kernel_module_request), .kernel_module_from_file = LIST_HEAD_INIT(security_hook_heads.kernel_module_from_file), + .kernel_read_file = + LIST_HEAD_INIT(security_hook_heads.kernel_read_file), .kernel_post_read_file = LIST_HEAD_INIT(security_hook_heads.kernel_post_read_file), .task_fix_setuid = -- cgit From b844f0ecbc5626ec26cfc70cb144a4c9b85dc3f2 Mon Sep 17 00:00:00 2001 From: Mimi Zohar Date: Mon, 1 Feb 2016 08:36:21 -0500 Subject: vfs: define kernel_copy_file_from_fd() This patch defines kernel_read_file_from_fd(), a wrapper for the VFS common kernel_read_file(). Changelog: - Separated from the kernel modules patch Acked-by: Kees Cook Acked-by: Luis R. Rodriguez Cc: Al Viro Signed-off-by: Mimi Zohar --- fs/exec.c | 16 ++++++++++++++++ include/linux/fs.h | 2 ++ 2 files changed, 18 insertions(+) (limited to 'fs/exec.c') diff --git a/fs/exec.c b/fs/exec.c index 8aaa38666119..9bdf0edf570d 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -907,6 +907,22 @@ int kernel_read_file_from_path(char *path, void **buf, loff_t *size, } EXPORT_SYMBOL_GPL(kernel_read_file_from_path); +int kernel_read_file_from_fd(int fd, void **buf, loff_t *size, loff_t max_size, + enum kernel_read_file_id id) +{ + struct fd f = fdget(fd); + int ret = -EBADF; + + if (!f.file) + goto out; + + ret = kernel_read_file(f.file, buf, size, max_size, id); +out: + fdput(f); + return ret; +} +EXPORT_SYMBOL_GPL(kernel_read_file_from_fd); + ssize_t read_code(struct file *file, unsigned long addr, loff_t pos, size_t len) { ssize_t res = vfs_read(file, (void __user *)addr, len, &pos); diff --git a/include/linux/fs.h b/include/linux/fs.h index c8bc4d8c843f..9c85deae1bf2 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2586,6 +2586,8 @@ extern int kernel_read_file(struct file *, void **, loff_t *, loff_t, enum kernel_read_file_id); extern int kernel_read_file_from_path(char *, void **, loff_t *, loff_t, enum kernel_read_file_id); +extern int kernel_read_file_from_fd(int, void **, loff_t *, loff_t, + enum kernel_read_file_id); extern ssize_t kernel_write(struct file *, const char *, size_t, loff_t); extern ssize_t __kernel_write(struct file *, const char *, size_t, loff_t *); extern struct file * open_exec(const char *); -- cgit