Commit dabba872 authored by Pasha Tatashin's avatar Pasha Tatashin Committed by akpm

fs/kernel_read_file: allow to read files up-to ssize_t

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.comSigned-off-by: default avatarPasha 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: default avatarAndrew Morton <akpm@linux-foundation.org>
parent d30dfd49
...@@ -29,15 +29,15 @@ ...@@ -29,15 +29,15 @@
* change between calls to kernel_read_file(). * change between calls to kernel_read_file().
* *
* Returns number of bytes read (no single read will be bigger * 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, ssize_t kernel_read_file(struct file *file, loff_t offset, void **buf,
size_t buf_size, size_t *file_size, size_t buf_size, size_t *file_size,
enum kernel_read_file_id id) enum kernel_read_file_id id)
{ {
loff_t i_size, pos; loff_t i_size, pos;
size_t copied; ssize_t copied;
void *allocated = NULL; void *allocated = NULL;
bool whole_file; bool whole_file;
int ret; int ret;
...@@ -58,7 +58,7 @@ int kernel_read_file(struct file *file, loff_t offset, void **buf, ...@@ -58,7 +58,7 @@ int kernel_read_file(struct file *file, loff_t offset, void **buf,
goto out; goto out;
} }
/* The file is too big for sane activities. */ /* The file is too big for sane activities. */
if (i_size > INT_MAX) { if (i_size > SSIZE_MAX) {
ret = -EFBIG; ret = -EFBIG;
goto out; goto out;
} }
...@@ -124,12 +124,12 @@ int kernel_read_file(struct file *file, loff_t offset, void **buf, ...@@ -124,12 +124,12 @@ int kernel_read_file(struct file *file, loff_t offset, void **buf,
} }
EXPORT_SYMBOL_GPL(kernel_read_file); EXPORT_SYMBOL_GPL(kernel_read_file);
int kernel_read_file_from_path(const char *path, loff_t offset, void **buf, ssize_t kernel_read_file_from_path(const char *path, loff_t offset, void **buf,
size_t buf_size, size_t *file_size, size_t buf_size, size_t *file_size,
enum kernel_read_file_id id) enum kernel_read_file_id id)
{ {
struct file *file; struct file *file;
int ret; ssize_t ret;
if (!path || !*path) if (!path || !*path)
return -EINVAL; return -EINVAL;
...@@ -144,14 +144,14 @@ int kernel_read_file_from_path(const char *path, loff_t offset, void **buf, ...@@ -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); EXPORT_SYMBOL_GPL(kernel_read_file_from_path);
int kernel_read_file_from_path_initns(const char *path, loff_t offset, ssize_t kernel_read_file_from_path_initns(const char *path, loff_t offset,
void **buf, size_t buf_size, void **buf, size_t buf_size,
size_t *file_size, size_t *file_size,
enum kernel_read_file_id id) enum kernel_read_file_id id)
{ {
struct file *file; struct file *file;
struct path root; struct path root;
int ret; ssize_t ret;
if (!path || !*path) if (!path || !*path)
return -EINVAL; return -EINVAL;
...@@ -171,12 +171,12 @@ int kernel_read_file_from_path_initns(const char *path, loff_t offset, ...@@ -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); EXPORT_SYMBOL_GPL(kernel_read_file_from_path_initns);
int kernel_read_file_from_fd(int fd, loff_t offset, void **buf, ssize_t kernel_read_file_from_fd(int fd, loff_t offset, void **buf,
size_t buf_size, size_t *file_size, size_t buf_size, size_t *file_size,
enum kernel_read_file_id id) enum kernel_read_file_id id)
{ {
struct fd f = fdget(fd); struct fd f = fdget(fd);
int ret = -EBADF; ssize_t ret = -EBADF;
if (!f.file || !(f.file->f_mode & FMODE_READ)) if (!f.file || !(f.file->f_mode & FMODE_READ))
goto out; goto out;
......
...@@ -35,21 +35,21 @@ static inline const char *kernel_read_file_id_str(enum kernel_read_file_id id) ...@@ -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]; return kernel_read_file_str[id];
} }
int kernel_read_file(struct file *file, loff_t offset, ssize_t kernel_read_file(struct file *file, loff_t offset,
void **buf, size_t buf_size, void **buf, size_t buf_size,
size_t *file_size, size_t *file_size,
enum kernel_read_file_id id); enum kernel_read_file_id id);
int kernel_read_file_from_path(const char *path, loff_t offset, ssize_t kernel_read_file_from_path(const char *path, loff_t offset,
void **buf, size_t buf_size, void **buf, size_t buf_size,
size_t *file_size, size_t *file_size,
enum kernel_read_file_id id); enum kernel_read_file_id id);
int kernel_read_file_from_path_initns(const char *path, loff_t offset, ssize_t kernel_read_file_from_path_initns(const char *path, loff_t offset,
void **buf, size_t buf_size, void **buf, size_t buf_size,
size_t *file_size, size_t *file_size,
enum kernel_read_file_id id); enum kernel_read_file_id id);
int kernel_read_file_from_fd(int fd, loff_t offset, ssize_t kernel_read_file_from_fd(int fd, loff_t offset,
void **buf, size_t buf_size, void **buf, size_t buf_size,
size_t *file_size, size_t *file_size,
enum kernel_read_file_id id); enum kernel_read_file_id id);
#endif /* _LINUX_KERNEL_READ_FILE_H */ #endif /* _LINUX_KERNEL_READ_FILE_H */
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <vdso/limits.h> #include <vdso/limits.h>
#define SIZE_MAX (~(size_t)0) #define SIZE_MAX (~(size_t)0)
#define SSIZE_MAX ((ssize_t)(SIZE_MAX >> 1))
#define PHYS_ADDR_MAX (~(phys_addr_t)0) #define PHYS_ADDR_MAX (~(phys_addr_t)0)
#define U8_MAX ((u8)~0U) #define U8_MAX ((u8)~0U)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment