lkml.org 
[lkml]   [2020]   [Feb]   [19]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v2 1/7] fs: introduce kernel_pread_file* support
    Date
    Add kernel_pread_file* support to kernel to allow for partial read
    of files with an offset into the file. Existing kernel_read_file
    functions call new kernel_pread_file functions with offset=0 and
    flags=KERNEL_PREAD_FLAG_WHOLE.

    Signed-off-by: Scott Branden <scott.branden@broadcom.com>
    ---
    fs/exec.c | 77 ++++++++++++++++++++++++++++++++++++----------
    include/linux/fs.h | 15 +++++++++
    2 files changed, 75 insertions(+), 17 deletions(-)

    diff --git a/fs/exec.c b/fs/exec.c
    index db17be51b112..a38f8fb432fa 100644
    --- a/fs/exec.c
    +++ b/fs/exec.c
    @@ -896,10 +896,14 @@ 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;
    +int kernel_pread_file(struct file *file, void **buf, loff_t *size,
    + loff_t pos, loff_t max_size, unsigned int flags,
    + enum kernel_read_file_id id)
    +{
    + loff_t alloc_size;
    + loff_t buf_pos;
    + loff_t read_end;
    + loff_t i_size;
    ssize_t bytes = 0;
    int ret;

    @@ -919,21 +923,31 @@ int kernel_read_file(struct file *file, void **buf, loff_t *size,
    ret = -EINVAL;
    goto out;
    }
    - if (i_size > SIZE_MAX || (max_size > 0 && i_size > max_size)) {
    +
    + /* Default read to end of file */
    + read_end = i_size;
    +
    + /* Allow reading partial portion of file */
    + if ((flags & KERNEL_PREAD_FLAG_PART) &&
    + (i_size > (pos + max_size)))
    + read_end = pos + max_size;
    +
    + alloc_size = read_end - pos;
    + if (i_size > SIZE_MAX || (max_size > 0 && alloc_size > max_size)) {
    ret = -EFBIG;
    goto out;
    }

    if (id != READING_FIRMWARE_PREALLOC_BUFFER)
    - *buf = vmalloc(i_size);
    + *buf = vmalloc(alloc_size);
    if (!*buf) {
    ret = -ENOMEM;
    goto out;
    }

    - pos = 0;
    - while (pos < i_size) {
    - bytes = kernel_read(file, *buf + pos, i_size - pos, &pos);
    + buf_pos = 0;
    + while (pos < read_end) {
    + bytes = kernel_read(file, *buf + buf_pos, read_end - pos, &pos);
    if (bytes < 0) {
    ret = bytes;
    goto out_free;
    @@ -941,14 +955,16 @@ int kernel_read_file(struct file *file, void **buf, loff_t *size,

    if (bytes == 0)
    break;
    +
    + buf_pos += bytes;
    }

    - if (pos != i_size) {
    + if (pos != read_end) {
    ret = -EIO;
    goto out_free;
    }

    - ret = security_kernel_post_read_file(file, *buf, i_size, id);
    + ret = security_kernel_post_read_file(file, *buf, alloc_size, id);
    if (!ret)
    *size = pos;

    @@ -964,10 +980,20 @@ int kernel_read_file(struct file *file, void **buf, loff_t *size,
    allow_write_access(file);
    return ret;
    }
    +EXPORT_SYMBOL_GPL(kernel_pread_file);
    +
    +int kernel_read_file(struct file *file, void **buf, loff_t *size,
    + loff_t max_size, enum kernel_read_file_id id)
    +{
    + return kernel_pread_file(file, buf, size, 0, max_size,
    + KERNEL_PREAD_FLAG_WHOLE, id);
    +}
    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)
    +int kernel_pread_file_from_path(const char *path, void **buf,
    + loff_t *size, loff_t pos,
    + loff_t max_size, unsigned int flags,
    + enum kernel_read_file_id id)
    {
    struct file *file;
    int ret;
    @@ -979,14 +1005,23 @@ int kernel_read_file_from_path(const char *path, void **buf, loff_t *size,
    if (IS_ERR(file))
    return PTR_ERR(file);

    - ret = kernel_read_file(file, buf, size, max_size, id);
    + ret = kernel_pread_file(file, buf, size, pos, max_size, flags, id);
    fput(file);
    return ret;
    }
    +EXPORT_SYMBOL_GPL(kernel_pread_file_from_path);
    +
    +int kernel_read_file_from_path(const char *path, void **buf, loff_t *size,
    + loff_t max_size, enum kernel_read_file_id id)
    +{
    + return kernel_pread_file_from_path(path, buf, size, 0, max_size,
    + KERNEL_PREAD_FLAG_WHOLE, id);
    +}
    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)
    +int kernel_pread_file_from_fd(int fd, void **buf, loff_t *size, loff_t pos,
    + loff_t max_size, unsigned int flags,
    + enum kernel_read_file_id id)
    {
    struct fd f = fdget(fd);
    int ret = -EBADF;
    @@ -994,11 +1029,19 @@ int kernel_read_file_from_fd(int fd, void **buf, loff_t *size, loff_t max_size,
    if (!f.file)
    goto out;

    - ret = kernel_read_file(f.file, buf, size, max_size, id);
    + ret = kernel_pread_file(f.file, buf, size, pos, max_size, flags, id);
    out:
    fdput(f);
    return ret;
    }
    +EXPORT_SYMBOL_GPL(kernel_pread_file_from_fd);
    +
    +int kernel_read_file_from_fd(int fd, void **buf, loff_t *size, loff_t max_size,
    + enum kernel_read_file_id id)
    +{
    + return kernel_pread_file_from_fd(fd, buf, size, 0, max_size,
    + KERNEL_PREAD_FLAG_WHOLE, id);
    +}
    EXPORT_SYMBOL_GPL(kernel_read_file_from_fd);

    ssize_t read_code(struct file *file, unsigned long addr, loff_t pos, size_t len)
    diff --git a/include/linux/fs.h b/include/linux/fs.h
    index 3cd4fe6b845e..8f39530cfcc2 100644
    --- a/include/linux/fs.h
    +++ b/include/linux/fs.h
    @@ -3008,10 +3008,25 @@ static inline const char *kernel_read_file_id_str(enum kernel_read_file_id id)
    return kernel_read_file_str[id];
    }

    +/* Flags used by kernel_pread_file functions */
    +#define KERNEL_PREAD_FLAG_WHOLE 0x0000 /* Only Allow reading of whole file */
    +#define KERNEL_PREAD_FLAG_PART 0x0001 /* Allow reading part of file */
    +
    +extern int kernel_pread_file(struct file *file, void **buf, loff_t *size,
    + loff_t pos, loff_t max_size, unsigned int flags,
    + enum kernel_read_file_id id);
    extern int kernel_read_file(struct file *, void **, loff_t *, loff_t,
    enum kernel_read_file_id);
    +extern int kernel_pread_file_from_path(const char *path, void **buf,
    + loff_t *size, loff_t pos,
    + loff_t max_size, unsigned int flags,
    + enum kernel_read_file_id id);
    extern int kernel_read_file_from_path(const char *, void **, loff_t *, loff_t,
    enum kernel_read_file_id);
    +extern int kernel_pread_file_from_fd(int fd, void **buf, loff_t *size,
    + loff_t pos, loff_t max_size,
    + unsigned int flags,
    + enum kernel_read_file_id id);
    extern int kernel_read_file_from_fd(int, void **, loff_t *, loff_t,
    enum kernel_read_file_id);
    extern ssize_t kernel_read(struct file *, void *, size_t, loff_t *);
    --
    2.17.1
    \
     
     \ /
      Last update: 2020-02-20 01:49    [W:4.656 / U:0.004 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site