fs/kernel_read_file: Add file_size output argument
[linux-2.6-microblaze.git] / fs / kernel_read_file.c
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  * @buf         pointer to a "void *" buffer for reading into (if
13  *              *@buf is NULL, a buffer will be allocated, and
14  *              @buf_size will be ignored)
15  * @buf_size    size of buf, if already allocated. If @buf not
16  *              allocated, this is the largest size to allocate.
17  * @file_size   if non-NULL, the full size of @file will be
18  *              written here.
19  * @id          the kernel_read_file_id identifying the type of
20  *              file contents being read (for LSMs to examine)
21  *
22  * Returns number of bytes read (no single read will be bigger
23  * than INT_MAX), or negative on error.
24  *
25  */
26 int kernel_read_file(struct file *file, void **buf,
27                      size_t buf_size, size_t *file_size,
28                      enum kernel_read_file_id id)
29 {
30         loff_t i_size, pos;
31         ssize_t bytes = 0;
32         void *allocated = NULL;
33         int ret;
34
35         if (!S_ISREG(file_inode(file)->i_mode))
36                 return -EINVAL;
37
38         ret = deny_write_access(file);
39         if (ret)
40                 return ret;
41
42         ret = security_kernel_read_file(file, id);
43         if (ret)
44                 goto out;
45
46         i_size = i_size_read(file_inode(file));
47         if (i_size <= 0) {
48                 ret = -EINVAL;
49                 goto out;
50         }
51         if (i_size > INT_MAX || i_size > buf_size) {
52                 ret = -EFBIG;
53                 goto out;
54         }
55         if (file_size)
56                 *file_size = i_size;
57
58         if (!*buf)
59                 *buf = allocated = vmalloc(i_size);
60         if (!*buf) {
61                 ret = -ENOMEM;
62                 goto out;
63         }
64
65         pos = 0;
66         while (pos < i_size) {
67                 bytes = kernel_read(file, *buf + pos, i_size - pos, &pos);
68                 if (bytes < 0) {
69                         ret = bytes;
70                         goto out_free;
71                 }
72
73                 if (bytes == 0)
74                         break;
75         }
76
77         if (pos != i_size) {
78                 ret = -EIO;
79                 goto out_free;
80         }
81
82         ret = security_kernel_post_read_file(file, *buf, i_size, id);
83
84 out_free:
85         if (ret < 0) {
86                 if (allocated) {
87                         vfree(*buf);
88                         *buf = NULL;
89                 }
90         }
91
92 out:
93         allow_write_access(file);
94         return ret == 0 ? pos : ret;
95 }
96 EXPORT_SYMBOL_GPL(kernel_read_file);
97
98 int kernel_read_file_from_path(const char *path, void **buf,
99                                size_t buf_size, size_t *file_size,
100                                enum kernel_read_file_id id)
101 {
102         struct file *file;
103         int ret;
104
105         if (!path || !*path)
106                 return -EINVAL;
107
108         file = filp_open(path, O_RDONLY, 0);
109         if (IS_ERR(file))
110                 return PTR_ERR(file);
111
112         ret = kernel_read_file(file, buf, buf_size, file_size, id);
113         fput(file);
114         return ret;
115 }
116 EXPORT_SYMBOL_GPL(kernel_read_file_from_path);
117
118 int kernel_read_file_from_path_initns(const char *path, void **buf,
119                                       size_t buf_size, size_t *file_size,
120                                       enum kernel_read_file_id id)
121 {
122         struct file *file;
123         struct path root;
124         int ret;
125
126         if (!path || !*path)
127                 return -EINVAL;
128
129         task_lock(&init_task);
130         get_fs_root(init_task.fs, &root);
131         task_unlock(&init_task);
132
133         file = file_open_root(root.dentry, root.mnt, path, O_RDONLY, 0);
134         path_put(&root);
135         if (IS_ERR(file))
136                 return PTR_ERR(file);
137
138         ret = kernel_read_file(file, buf, buf_size, file_size, id);
139         fput(file);
140         return ret;
141 }
142 EXPORT_SYMBOL_GPL(kernel_read_file_from_path_initns);
143
144 int kernel_read_file_from_fd(int fd, void **buf, size_t buf_size,
145                              size_t *file_size,
146                              enum kernel_read_file_id id)
147 {
148         struct fd f = fdget(fd);
149         int ret = -EBADF;
150
151         if (!f.file)
152                 goto out;
153
154         ret = kernel_read_file(f.file, buf, buf_size, file_size, id);
155 out:
156         fdput(f);
157         return ret;
158 }
159 EXPORT_SYMBOL_GPL(kernel_read_file_from_fd);