fs/kernel_read_file: allow to read files up-to ssize_t
authorPasha Tatashin <pasha.tatashin@soleen.com>
Fri, 27 May 2022 02:55:34 +0000 (02:55 +0000)
committerakpm <akpm@linux-foundation.org>
Fri, 17 Jun 2022 02:58:21 +0000 (19:58 -0700)
Patch series "Allow to kexec with initramfs larger than 2G", v2.

Currently, the largest initramfs that is supported by kexec_file_load()
syscall is 2G.

This is because kernel_read_file() returns int, and is limited to INT_MAX
or 2G.

On the other hand, there are kexec based boot loaders (i.e.  u-root), that
may need to boot netboot images that might be larger than 2G.

The first patch changes the return type from int to ssize_t in
kernel_read_file* functions.

The second patch increases the maximum initramfs file size to 4G.

Tested: verified that can kexec_file_load() works with 4G initramfs
on x86_64.

This patch (of 2):

Currently, the maximum file size that is supported is 2G.  This may be too
small in some cases.  For example, kexec_file_load() system call loads
initramfs.  In some netboot cases initramfs can be rather large.

Allow to use up-to ssize_t bytes.  The callers still can limit the maximum
file size via buf_size.

Link: https://lkml.kernel.org/r/20220527025535.3953665-1-pasha.tatashin@soleen.com
Link: https://lkml.kernel.org/r/20220527025535.3953665-2-pasha.tatashin@soleen.com
Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Baoquan He <bhe@redhat.com>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Cc: Greg Thelen <gthelen@google.com>
Cc: Sasha Levin <sashal@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
fs/kernel_read_file.c
include/linux/kernel_read_file.h
include/linux/limits.h

index 1b07550485b96415f0a79a7029b10bf5d78c643e..5d826274570cab055b310b4fca2437d6b87f9995 100644 (file)
  * change between calls to kernel_read_file().
  *
  * Returns number of bytes read (no single read will be bigger
- * than INT_MAX), or negative on error.
+ * than SSIZE_MAX), or negative on error.
  *
  */
-int kernel_read_file(struct file *file, loff_t offset, void **buf,
-                    size_t buf_size, size_t *file_size,
-                    enum kernel_read_file_id id)
+ssize_t kernel_read_file(struct file *file, loff_t offset, void **buf,
+                        size_t buf_size, size_t *file_size,
+                        enum kernel_read_file_id id)
 {
        loff_t i_size, pos;
-       size_t copied;
+       ssize_t copied;
        void *allocated = NULL;
        bool whole_file;
        int ret;
@@ -58,7 +58,7 @@ int kernel_read_file(struct file *file, loff_t offset, void **buf,
                goto out;
        }
        /* The file is too big for sane activities. */
-       if (i_size > INT_MAX) {
+       if (i_size > SSIZE_MAX) {
                ret = -EFBIG;
                goto out;
        }
@@ -124,12 +124,12 @@ out:
 }
 EXPORT_SYMBOL_GPL(kernel_read_file);
 
-int kernel_read_file_from_path(const char *path, loff_t offset, void **buf,
-                              size_t buf_size, size_t *file_size,
-                              enum kernel_read_file_id id)
+ssize_t kernel_read_file_from_path(const char *path, loff_t offset, void **buf,
+                                  size_t buf_size, size_t *file_size,
+                                  enum kernel_read_file_id id)
 {
        struct file *file;
-       int ret;
+       ssize_t ret;
 
        if (!path || !*path)
                return -EINVAL;
@@ -144,14 +144,14 @@ int kernel_read_file_from_path(const char *path, loff_t offset, void **buf,
 }
 EXPORT_SYMBOL_GPL(kernel_read_file_from_path);
 
-int kernel_read_file_from_path_initns(const char *path, loff_t offset,
-                                     void **buf, size_t buf_size,
-                                     size_t *file_size,
-                                     enum kernel_read_file_id id)
+ssize_t kernel_read_file_from_path_initns(const char *path, loff_t offset,
+                                         void **buf, size_t buf_size,
+                                         size_t *file_size,
+                                         enum kernel_read_file_id id)
 {
        struct file *file;
        struct path root;
-       int ret;
+       ssize_t ret;
 
        if (!path || !*path)
                return -EINVAL;
@@ -171,12 +171,12 @@ int kernel_read_file_from_path_initns(const char *path, loff_t offset,
 }
 EXPORT_SYMBOL_GPL(kernel_read_file_from_path_initns);
 
-int kernel_read_file_from_fd(int fd, loff_t offset, void **buf,
-                            size_t buf_size, size_t *file_size,
-                            enum kernel_read_file_id id)
+ssize_t kernel_read_file_from_fd(int fd, loff_t offset, void **buf,
+                                size_t buf_size, size_t *file_size,
+                                enum kernel_read_file_id id)
 {
        struct fd f = fdget(fd);
-       int ret = -EBADF;
+       ssize_t ret = -EBADF;
 
        if (!f.file || !(f.file->f_mode & FMODE_READ))
                goto out;
index 575ffa1031d348e2fb11ac9a556b443dea365030..90451e2e12bd19eeb436ad59ad83d7ab1168e26b 100644 (file)
@@ -35,21 +35,21 @@ static inline const char *kernel_read_file_id_str(enum kernel_read_file_id id)
        return kernel_read_file_str[id];
 }
 
-int kernel_read_file(struct file *file, loff_t offset,
-                    void **buf, size_t buf_size,
-                    size_t *file_size,
-                    enum kernel_read_file_id id);
-int kernel_read_file_from_path(const char *path, loff_t offset,
-                              void **buf, size_t buf_size,
-                              size_t *file_size,
-                              enum kernel_read_file_id id);
-int kernel_read_file_from_path_initns(const char *path, loff_t offset,
-                                     void **buf, size_t buf_size,
-                                     size_t *file_size,
-                                     enum kernel_read_file_id id);
-int kernel_read_file_from_fd(int fd, loff_t offset,
-                            void **buf, size_t buf_size,
-                            size_t *file_size,
-                            enum kernel_read_file_id id);
+ssize_t kernel_read_file(struct file *file, loff_t offset,
+                        void **buf, size_t buf_size,
+                        size_t *file_size,
+                        enum kernel_read_file_id id);
+ssize_t kernel_read_file_from_path(const char *path, loff_t offset,
+                                  void **buf, size_t buf_size,
+                                  size_t *file_size,
+                                  enum kernel_read_file_id id);
+ssize_t kernel_read_file_from_path_initns(const char *path, loff_t offset,
+                                         void **buf, size_t buf_size,
+                                         size_t *file_size,
+                                         enum kernel_read_file_id id);
+ssize_t kernel_read_file_from_fd(int fd, loff_t offset,
+                                void **buf, size_t buf_size,
+                                size_t *file_size,
+                                enum kernel_read_file_id id);
 
 #endif /* _LINUX_KERNEL_READ_FILE_H */
index b568b9c30bbf58073fd44c44dd5f1a03de91f9c3..f6bcc936901071f496e3e85bb6e1d93905b12e32 100644 (file)
@@ -7,6 +7,7 @@
 #include <vdso/limits.h>
 
 #define SIZE_MAX       (~(size_t)0)
+#define SSIZE_MAX      ((ssize_t)(SIZE_MAX >> 1))
 #define PHYS_ADDR_MAX  (~(phys_addr_t)0)
 
 #define U8_MAX         ((u8)~0U)