~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/kernel_read_file.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 #include <linux/fs.h>
  3 #include <linux/fs_struct.h>
  4 #include <linux/kernel_read_file.h>
  5 #include <linux/security.h>
  6 #include <linux/vmalloc.h>
  7 
  8 /**
  9  * kernel_read_file() - read file contents into a kernel buffer
 10  *
 11  * @file:       file to read from
 12  * @offset:     where to start reading from (see below).
 13  * @buf:        pointer to a "void *" buffer for reading into (if
 14  *              *@buf is NULL, a buffer will be allocated, and
 15  *              @buf_size will be ignored)
 16  * @buf_size:   size of buf, if already allocated. If @buf not
 17  *              allocated, this is the largest size to allocate.
 18  * @file_size:  if non-NULL, the full size of @file will be
 19  *              written here.
 20  * @id:         the kernel_read_file_id identifying the type of
 21  *              file contents being read (for LSMs to examine)
 22  *
 23  * @offset must be 0 unless both @buf and @file_size are non-NULL
 24  * (i.e. the caller must be expecting to read partial file contents
 25  * via an already-allocated @buf, in at most @buf_size chunks, and
 26  * will be able to determine when the entire file was read by
 27  * checking @file_size). This isn't a recommended way to read a
 28  * file, though, since it is possible that the contents might
 29  * change between calls to kernel_read_file().
 30  *
 31  * Returns number of bytes read (no single read will be bigger
 32  * than SSIZE_MAX), or negative on error.
 33  *
 34  */
 35 ssize_t kernel_read_file(struct file *file, loff_t offset, void **buf,
 36                          size_t buf_size, size_t *file_size,
 37                          enum kernel_read_file_id id)
 38 {
 39         loff_t i_size, pos;
 40         ssize_t copied;
 41         void *allocated = NULL;
 42         bool whole_file;
 43         int ret;
 44 
 45         if (offset != 0 && (!*buf || !file_size))
 46                 return -EINVAL;
 47 
 48         if (!S_ISREG(file_inode(file)->i_mode))
 49                 return -EINVAL;
 50 
 51         ret = deny_write_access(file);
 52         if (ret)
 53                 return ret;
 54 
 55         i_size = i_size_read(file_inode(file));
 56         if (i_size <= 0) {
 57                 ret = -EINVAL;
 58                 goto out;
 59         }
 60         /* The file is too big for sane activities. */
 61         if (i_size > SSIZE_MAX) {
 62                 ret = -EFBIG;
 63                 goto out;
 64         }
 65         /* The entire file cannot be read in one buffer. */
 66         if (!file_size && offset == 0 && i_size > buf_size) {
 67                 ret = -EFBIG;
 68                 goto out;
 69         }
 70 
 71         whole_file = (offset == 0 && i_size <= buf_size);
 72         ret = security_kernel_read_file(file, id, whole_file);
 73         if (ret)
 74                 goto out;
 75 
 76         if (file_size)
 77                 *file_size = i_size;
 78 
 79         if (!*buf)
 80                 *buf = allocated = vmalloc(i_size);
 81         if (!*buf) {
 82                 ret = -ENOMEM;
 83                 goto out;
 84         }
 85 
 86         pos = offset;
 87         copied = 0;
 88         while (copied < buf_size) {
 89                 ssize_t bytes;
 90                 size_t wanted = min_t(size_t, buf_size - copied,
 91                                               i_size - pos);
 92 
 93                 bytes = kernel_read(file, *buf + copied, wanted, &pos);
 94                 if (bytes < 0) {
 95                         ret = bytes;
 96                         goto out_free;
 97                 }
 98 
 99                 if (bytes == 0)
100                         break;
101                 copied += bytes;
102         }
103 
104         if (whole_file) {
105                 if (pos != i_size) {
106                         ret = -EIO;
107                         goto out_free;
108                 }
109 
110                 ret = security_kernel_post_read_file(file, *buf, i_size, id);
111         }
112 
113 out_free:
114         if (ret < 0) {
115                 if (allocated) {
116                         vfree(*buf);
117                         *buf = NULL;
118                 }
119         }
120 
121 out:
122         allow_write_access(file);
123         return ret == 0 ? copied : ret;
124 }
125 EXPORT_SYMBOL_GPL(kernel_read_file);
126 
127 ssize_t kernel_read_file_from_path(const char *path, loff_t offset, void **buf,
128                                    size_t buf_size, size_t *file_size,
129                                    enum kernel_read_file_id id)
130 {
131         struct file *file;
132         ssize_t ret;
133 
134         if (!path || !*path)
135                 return -EINVAL;
136 
137         file = filp_open(path, O_RDONLY, 0);
138         if (IS_ERR(file))
139                 return PTR_ERR(file);
140 
141         ret = kernel_read_file(file, offset, buf, buf_size, file_size, id);
142         fput(file);
143         return ret;
144 }
145 EXPORT_SYMBOL_GPL(kernel_read_file_from_path);
146 
147 ssize_t kernel_read_file_from_path_initns(const char *path, loff_t offset,
148                                           void **buf, size_t buf_size,
149                                           size_t *file_size,
150                                           enum kernel_read_file_id id)
151 {
152         struct file *file;
153         struct path root;
154         ssize_t ret;
155 
156         if (!path || !*path)
157                 return -EINVAL;
158 
159         task_lock(&init_task);
160         get_fs_root(init_task.fs, &root);
161         task_unlock(&init_task);
162 
163         file = file_open_root(&root, path, O_RDONLY, 0);
164         path_put(&root);
165         if (IS_ERR(file))
166                 return PTR_ERR(file);
167 
168         ret = kernel_read_file(file, offset, buf, buf_size, file_size, id);
169         fput(file);
170         return ret;
171 }
172 EXPORT_SYMBOL_GPL(kernel_read_file_from_path_initns);
173 
174 ssize_t kernel_read_file_from_fd(int fd, loff_t offset, void **buf,
175                                  size_t buf_size, size_t *file_size,
176                                  enum kernel_read_file_id id)
177 {
178         struct fd f = fdget(fd);
179         ssize_t ret = -EBADF;
180 
181         if (!f.file || !(f.file->f_mode & FMODE_READ))
182                 goto out;
183 
184         ret = kernel_read_file(f.file, offset, buf, buf_size, file_size, id);
185 out:
186         fdput(f);
187         return ret;
188 }
189 EXPORT_SYMBOL_GPL(kernel_read_file_from_fd);
190 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php