fs/kernel_read_file: Split into separate source file
authorKees Cook <keescook@chromium.org>
Fri, 2 Oct 2020 17:38:16 +0000 (10:38 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 5 Oct 2020 11:34:18 +0000 (13:34 +0200)
These routines are used in places outside of exec(2), so in preparation
for refactoring them, move them into a separate source file,
fs/kernel_read_file.c.

Signed-off-by: Kees Cook <keescook@chromium.org>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
Reviewed-by: Luis Chamberlain <mcgrof@kernel.org>
Acked-by: Scott Branden <scott.branden@broadcom.com>
Link: https://lore.kernel.org/r/20201002173828.2099543-5-keescook@chromium.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/Makefile
fs/exec.c
fs/kernel_read_file.c [new file with mode: 0644]

index 1c7b0e3..40c19ff 100644 (file)
@@ -13,7 +13,8 @@ obj-y :=      open.o read_write.o file_table.o super.o \
                seq_file.o xattr.o libfs.o fs-writeback.o \
                pnode.o splice.o sync.o utimes.o d_path.o \
                stack.o fs_struct.o statfs.o fs_pin.o nsfs.o \
-               fs_types.o fs_context.o fs_parser.o fsopen.o init.o
+               fs_types.o fs_context.o fs_parser.o fsopen.o init.o \
+               kernel_read_file.o
 
 ifeq ($(CONFIG_BLOCK),y)
 obj-y +=       buffer.o block_dev.o direct-io.o mpage.o
index c454af3..9f09440 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -950,138 +950,6 @@ struct file *open_exec(const char *name)
 }
 EXPORT_SYMBOL(open_exec);
 
-int kernel_read_file(struct file *file, void **buf, loff_t *size,
-                    loff_t max_size, enum kernel_read_file_id id)
-{
-       loff_t i_size, pos;
-       ssize_t bytes = 0;
-       void *allocated = NULL;
-       int ret;
-
-       if (!S_ISREG(file_inode(file)->i_mode) || max_size < 0)
-               return -EINVAL;
-
-       ret = deny_write_access(file);
-       if (ret)
-               return ret;
-
-       ret = security_kernel_read_file(file, id);
-       if (ret)
-               goto out;
-
-       i_size = i_size_read(file_inode(file));
-       if (i_size <= 0) {
-               ret = -EINVAL;
-               goto out;
-       }
-       if (i_size > SIZE_MAX || (max_size > 0 && i_size > max_size)) {
-               ret = -EFBIG;
-               goto out;
-       }
-
-       if (!*buf)
-               *buf = allocated = vmalloc(i_size);
-       if (!*buf) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       pos = 0;
-       while (pos < i_size) {
-               bytes = kernel_read(file, *buf + pos, i_size - pos, &pos);
-               if (bytes < 0) {
-                       ret = bytes;
-                       goto out_free;
-               }
-
-               if (bytes == 0)
-                       break;
-       }
-
-       if (pos != i_size) {
-               ret = -EIO;
-               goto out_free;
-       }
-
-       ret = security_kernel_post_read_file(file, *buf, i_size, id);
-       if (!ret)
-               *size = pos;
-
-out_free:
-       if (ret < 0) {
-               if (allocated) {
-                       vfree(*buf);
-                       *buf = NULL;
-               }
-       }
-
-out:
-       allow_write_access(file);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(kernel_read_file);
-
-int kernel_read_file_from_path(const 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);
-
-int kernel_read_file_from_path_initns(const char *path, void **buf,
-                                     loff_t *size, loff_t max_size,
-                                     enum kernel_read_file_id id)
-{
-       struct file *file;
-       struct path root;
-       int ret;
-
-       if (!path || !*path)
-               return -EINVAL;
-
-       task_lock(&init_task);
-       get_fs_root(init_task.fs, &root);
-       task_unlock(&init_task);
-
-       file = file_open_root(root.dentry, root.mnt, path, O_RDONLY, 0);
-       path_put(&root);
-       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_initns);
-
-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);
-
 #if defined(CONFIG_HAVE_AOUT) || defined(CONFIG_BINFMT_FLAT) || \
     defined(CONFIG_BINFMT_ELF_FDPIC)
 ssize_t read_code(struct file *file, unsigned long addr, loff_t pos, size_t len)
diff --git a/fs/kernel_read_file.c b/fs/kernel_read_file.c
new file mode 100644 (file)
index 0000000..54d972d
--- /dev/null
@@ -0,0 +1,138 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <linux/fs.h>
+#include <linux/fs_struct.h>
+#include <linux/kernel_read_file.h>
+#include <linux/security.h>
+#include <linux/vmalloc.h>
+
+int kernel_read_file(struct file *file, void **buf, loff_t *size,
+                    loff_t max_size, enum kernel_read_file_id id)
+{
+       loff_t i_size, pos;
+       ssize_t bytes = 0;
+       void *allocated = NULL;
+       int ret;
+
+       if (!S_ISREG(file_inode(file)->i_mode) || max_size < 0)
+               return -EINVAL;
+
+       ret = deny_write_access(file);
+       if (ret)
+               return ret;
+
+       ret = security_kernel_read_file(file, id);
+       if (ret)
+               goto out;
+
+       i_size = i_size_read(file_inode(file));
+       if (i_size <= 0) {
+               ret = -EINVAL;
+               goto out;
+       }
+       if (i_size > SIZE_MAX || (max_size > 0 && i_size > max_size)) {
+               ret = -EFBIG;
+               goto out;
+       }
+
+       if (!*buf)
+               *buf = allocated = vmalloc(i_size);
+       if (!*buf) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       pos = 0;
+       while (pos < i_size) {
+               bytes = kernel_read(file, *buf + pos, i_size - pos, &pos);
+               if (bytes < 0) {
+                       ret = bytes;
+                       goto out_free;
+               }
+
+               if (bytes == 0)
+                       break;
+       }
+
+       if (pos != i_size) {
+               ret = -EIO;
+               goto out_free;
+       }
+
+       ret = security_kernel_post_read_file(file, *buf, i_size, id);
+       if (!ret)
+               *size = pos;
+
+out_free:
+       if (ret < 0) {
+               if (allocated) {
+                       vfree(*buf);
+                       *buf = NULL;
+               }
+       }
+
+out:
+       allow_write_access(file);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(kernel_read_file);
+
+int kernel_read_file_from_path(const 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);
+
+int kernel_read_file_from_path_initns(const char *path, void **buf,
+                                     loff_t *size, loff_t max_size,
+                                     enum kernel_read_file_id id)
+{
+       struct file *file;
+       struct path root;
+       int ret;
+
+       if (!path || !*path)
+               return -EINVAL;
+
+       task_lock(&init_task);
+       get_fs_root(init_task.fs, &root);
+       task_unlock(&init_task);
+
+       file = file_open_root(root.dentry, root.mnt, path, O_RDONLY, 0);
+       path_put(&root);
+       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_initns);
+
+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);