Commit dabba872 authored by Pasha Tatashin's avatar Pasha Tatashin Committed by Andrew Morton
Browse files

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.com


Signed-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
Loading
Loading
Loading
Loading
+19 −19
Original line number Diff line number Diff line
@@ -29,15 +29,15 @@
 * 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,
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 @@ int kernel_read_file(struct file *file, loff_t offset, void **buf,
}
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,
				   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,
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,
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;
+16 −16
Original line number Diff line number Diff line
@@ -35,19 +35,19 @@ 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,
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);
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,
				   size_t *file_size,
				   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,
					  size_t *file_size,
					  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,
				 size_t *file_size,
				 enum kernel_read_file_id id);
+1 −0
Original line number Diff line number Diff line
@@ -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)