Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

fs/kernel_file_read: Add "offset" arg for partial reads

To perform partial reads, callers of kernel_read_file*() must have a
non-NULL file_size argument and a preallocated buffer. The new "offset"
argument can then be used to seek to specific locations in the file to
fill the buffer to, at most, "buf_size" per call.

Where possible, the LSM hooks can report whether a full file has been
read or not so that the contents can be reasoned about.

Signed-off-by: Kees Cook <keescook@chromium.org>
Link: https://lore.kernel.org/r/20201002173828.2099543-14-keescook@chromium.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Kees Cook and committed by
Greg Kroah-Hartman
0fa8e084 34736dae

+65 -34
+1 -1
drivers/base/firmware_loader/main.c
··· 499 499 fw_priv->size = 0; 500 500 501 501 /* load firmware files from the mount namespace of init */ 502 - rc = kernel_read_file_from_path_initns(path, &buffer, msize, 502 + rc = kernel_read_file_from_path_initns(path, 0, &buffer, msize, 503 503 NULL, 504 504 READING_FIRMWARE); 505 505 if (rc < 0) {
+54 -24
fs/kernel_read_file.c
··· 9 9 * kernel_read_file() - read file contents into a kernel buffer 10 10 * 11 11 * @file file to read from 12 + * @offset where to start reading from (see below). 12 13 * @buf pointer to a "void *" buffer for reading into (if 13 14 * *@buf is NULL, a buffer will be allocated, and 14 15 * @buf_size will be ignored) ··· 20 19 * @id the kernel_read_file_id identifying the type of 21 20 * file contents being read (for LSMs to examine) 22 21 * 22 + * @offset must be 0 unless both @buf and @file_size are non-NULL 23 + * (i.e. the caller must be expecting to read partial file contents 24 + * via an already-allocated @buf, in at most @buf_size chunks, and 25 + * will be able to determine when the entire file was read by 26 + * checking @file_size). This isn't a recommended way to read a 27 + * file, though, since it is possible that the contents might 28 + * change between calls to kernel_read_file(). 29 + * 23 30 * Returns number of bytes read (no single read will be bigger 24 31 * than INT_MAX), or negative on error. 25 32 * 26 33 */ 27 - int kernel_read_file(struct file *file, void **buf, 34 + int kernel_read_file(struct file *file, loff_t offset, void **buf, 28 35 size_t buf_size, size_t *file_size, 29 36 enum kernel_read_file_id id) 30 37 { 31 38 loff_t i_size, pos; 32 - ssize_t bytes = 0; 39 + size_t copied; 33 40 void *allocated = NULL; 41 + bool whole_file; 34 42 int ret; 43 + 44 + if (offset != 0 && (!*buf || !file_size)) 45 + return -EINVAL; 35 46 36 47 if (!S_ISREG(file_inode(file)->i_mode)) 37 48 return -EINVAL; ··· 52 39 if (ret) 53 40 return ret; 54 41 55 - ret = security_kernel_read_file(file, id, true); 56 - if (ret) 57 - goto out; 58 - 59 42 i_size = i_size_read(file_inode(file)); 60 43 if (i_size <= 0) { 61 44 ret = -EINVAL; 62 45 goto out; 63 46 } 64 - if (i_size > INT_MAX || i_size > buf_size) { 47 + /* The file is too big for sane activities. */ 48 + if (i_size > INT_MAX) { 65 49 ret = -EFBIG; 66 50 goto out; 67 51 } 52 + /* The entire file cannot be read in one buffer. */ 53 + if (!file_size && offset == 0 && i_size > buf_size) { 54 + ret = -EFBIG; 55 + goto out; 56 + } 57 + 58 + whole_file = (offset == 0 && i_size <= buf_size); 59 + ret = security_kernel_read_file(file, id, whole_file); 60 + if (ret) 61 + goto out; 62 + 68 63 if (file_size) 69 64 *file_size = i_size; 70 65 ··· 83 62 goto out; 84 63 } 85 64 86 - pos = 0; 87 - while (pos < i_size) { 88 - bytes = kernel_read(file, *buf + pos, i_size - pos, &pos); 65 + pos = offset; 66 + copied = 0; 67 + while (copied < buf_size) { 68 + ssize_t bytes; 69 + size_t wanted = min_t(size_t, buf_size - copied, 70 + i_size - pos); 71 + 72 + bytes = kernel_read(file, *buf + copied, wanted, &pos); 89 73 if (bytes < 0) { 90 74 ret = bytes; 91 75 goto out_free; ··· 98 72 99 73 if (bytes == 0) 100 74 break; 75 + copied += bytes; 101 76 } 102 77 103 - if (pos != i_size) { 104 - ret = -EIO; 105 - goto out_free; 106 - } 78 + if (whole_file) { 79 + if (pos != i_size) { 80 + ret = -EIO; 81 + goto out_free; 82 + } 107 83 108 - ret = security_kernel_post_read_file(file, *buf, i_size, id); 84 + ret = security_kernel_post_read_file(file, *buf, i_size, id); 85 + } 109 86 110 87 out_free: 111 88 if (ret < 0) { ··· 120 91 121 92 out: 122 93 allow_write_access(file); 123 - return ret == 0 ? pos : ret; 94 + return ret == 0 ? copied : ret; 124 95 } 125 96 EXPORT_SYMBOL_GPL(kernel_read_file); 126 97 127 - int kernel_read_file_from_path(const char *path, void **buf, 98 + int kernel_read_file_from_path(const char *path, loff_t offset, void **buf, 128 99 size_t buf_size, size_t *file_size, 129 100 enum kernel_read_file_id id) 130 101 { ··· 138 109 if (IS_ERR(file)) 139 110 return PTR_ERR(file); 140 111 141 - ret = kernel_read_file(file, buf, buf_size, file_size, id); 112 + ret = kernel_read_file(file, offset, buf, buf_size, file_size, id); 142 113 fput(file); 143 114 return ret; 144 115 } 145 116 EXPORT_SYMBOL_GPL(kernel_read_file_from_path); 146 117 147 - int kernel_read_file_from_path_initns(const char *path, void **buf, 148 - size_t buf_size, size_t *file_size, 118 + int kernel_read_file_from_path_initns(const char *path, loff_t offset, 119 + void **buf, size_t buf_size, 120 + size_t *file_size, 149 121 enum kernel_read_file_id id) 150 122 { 151 123 struct file *file; ··· 165 135 if (IS_ERR(file)) 166 136 return PTR_ERR(file); 167 137 168 - ret = kernel_read_file(file, buf, buf_size, file_size, id); 138 + ret = kernel_read_file(file, offset, buf, buf_size, file_size, id); 169 139 fput(file); 170 140 return ret; 171 141 } 172 142 EXPORT_SYMBOL_GPL(kernel_read_file_from_path_initns); 173 143 174 - int kernel_read_file_from_fd(int fd, void **buf, size_t buf_size, 175 - size_t *file_size, 144 + int kernel_read_file_from_fd(int fd, loff_t offset, void **buf, 145 + size_t buf_size, size_t *file_size, 176 146 enum kernel_read_file_id id) 177 147 { 178 148 struct fd f = fdget(fd); ··· 181 151 if (!f.file) 182 152 goto out; 183 153 184 - ret = kernel_read_file(f.file, buf, buf_size, file_size, id); 154 + ret = kernel_read_file(f.file, offset, buf, buf_size, file_size, id); 185 155 out: 186 156 fdput(f); 187 157 return ret;
+4 -4
include/linux/kernel_read_file.h
··· 35 35 return kernel_read_file_str[id]; 36 36 } 37 37 38 - int kernel_read_file(struct file *file, 38 + int kernel_read_file(struct file *file, loff_t offset, 39 39 void **buf, size_t buf_size, 40 40 size_t *file_size, 41 41 enum kernel_read_file_id id); 42 - int kernel_read_file_from_path(const char *path, 42 + int kernel_read_file_from_path(const char *path, loff_t offset, 43 43 void **buf, size_t buf_size, 44 44 size_t *file_size, 45 45 enum kernel_read_file_id id); 46 - int kernel_read_file_from_path_initns(const char *path, 46 + int kernel_read_file_from_path_initns(const char *path, loff_t offset, 47 47 void **buf, size_t buf_size, 48 48 size_t *file_size, 49 49 enum kernel_read_file_id id); 50 - int kernel_read_file_from_fd(int fd, 50 + int kernel_read_file_from_fd(int fd, loff_t offset, 51 51 void **buf, size_t buf_size, 52 52 size_t *file_size, 53 53 enum kernel_read_file_id id);
+2 -2
kernel/kexec_file.c
··· 221 221 int ret; 222 222 void *ldata; 223 223 224 - ret = kernel_read_file_from_fd(kernel_fd, &image->kernel_buf, 224 + ret = kernel_read_file_from_fd(kernel_fd, 0, &image->kernel_buf, 225 225 INT_MAX, NULL, READING_KEXEC_IMAGE); 226 226 if (ret < 0) 227 227 return ret; ··· 241 241 #endif 242 242 /* It is possible that there no initramfs is being loaded */ 243 243 if (!(flags & KEXEC_FILE_NO_INITRAMFS)) { 244 - ret = kernel_read_file_from_fd(initrd_fd, &image->initrd_buf, 244 + ret = kernel_read_file_from_fd(initrd_fd, 0, &image->initrd_buf, 245 245 INT_MAX, NULL, 246 246 READING_KEXEC_INITRAMFS); 247 247 if (ret < 0)
+1 -1
kernel/module.c
··· 4054 4054 |MODULE_INIT_IGNORE_VERMAGIC)) 4055 4055 return -EINVAL; 4056 4056 4057 - err = kernel_read_file_from_fd(fd, &hdr, INT_MAX, NULL, 4057 + err = kernel_read_file_from_fd(fd, 0, &hdr, INT_MAX, NULL, 4058 4058 READING_MODULE); 4059 4059 if (err < 0) 4060 4060 return err;
+1 -1
security/integrity/digsig.c
··· 175 175 int rc; 176 176 key_perm_t perm; 177 177 178 - rc = kernel_read_file_from_path(path, &data, INT_MAX, NULL, 178 + rc = kernel_read_file_from_path(path, 0, &data, INT_MAX, NULL, 179 179 READING_X509_CERTIFICATE); 180 180 if (rc < 0) { 181 181 pr_err("Unable to open file: %s (%d)", path, rc);
+2 -1
security/integrity/ima/ima_fs.c
··· 284 284 datap = path; 285 285 strsep(&datap, "\n"); 286 286 287 - rc = kernel_read_file_from_path(path, &data, INT_MAX, NULL, READING_POLICY); 287 + rc = kernel_read_file_from_path(path, 0, &data, INT_MAX, NULL, 288 + READING_POLICY); 288 289 if (rc < 0) { 289 290 pr_err("Unable to open file: %s (%d)", path, rc); 290 291 return rc;