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)
19
20
* @id the kernel_read_file_id identifying the type of
20
21
* file contents being read (for LSMs to examine)
21
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
+ *
22
31
* Returns number of bytes read (no single read will be bigger
23
32
* than INT_MAX), or negative on error.
24
33
*
25
34
*/
26
- int kernel_read_file (struct file * file , void * * buf ,
35
+ int kernel_read_file (struct file * file , loff_t offset , void * * buf ,
27
36
size_t buf_size , size_t * file_size ,
28
37
enum kernel_read_file_id id )
29
38
{
30
39
loff_t i_size , pos ;
31
- ssize_t bytes = 0 ;
40
+ size_t copied ;
32
41
void * allocated = NULL ;
42
+ bool whole_file ;
33
43
int ret ;
34
44
45
+ if (offset != 0 && (!* buf || !file_size ))
46
+ return - EINVAL ;
47
+
35
48
if (!S_ISREG (file_inode (file )-> i_mode ))
36
49
return - EINVAL ;
37
50
38
51
ret = deny_write_access (file );
39
52
if (ret )
40
53
return ret ;
41
54
42
- ret = security_kernel_read_file (file , id , true);
43
- if (ret )
44
- goto out ;
45
-
46
55
i_size = i_size_read (file_inode (file ));
47
56
if (i_size <= 0 ) {
48
57
ret = - EINVAL ;
49
58
goto out ;
50
59
}
51
- if (i_size > INT_MAX || i_size > buf_size ) {
60
+ /* The file is too big for sane activities. */
61
+ if (i_size > INT_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 ) {
52
67
ret = - EFBIG ;
53
68
goto out ;
54
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
+
55
76
if (file_size )
56
77
* file_size = i_size ;
57
78
@@ -62,24 +83,32 @@ int kernel_read_file(struct file *file, void **buf,
62
83
goto out ;
63
84
}
64
85
65
- pos = 0 ;
66
- while (pos < i_size ) {
67
- bytes = kernel_read (file , * buf + pos , i_size - pos , & pos );
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 );
68
94
if (bytes < 0 ) {
69
95
ret = bytes ;
70
96
goto out_free ;
71
97
}
72
98
73
99
if (bytes == 0 )
74
100
break ;
101
+ copied += bytes ;
75
102
}
76
103
77
- if (pos != i_size ) {
78
- ret = - EIO ;
79
- goto out_free ;
80
- }
104
+ if (whole_file ) {
105
+ if (pos != i_size ) {
106
+ ret = - EIO ;
107
+ goto out_free ;
108
+ }
81
109
82
- ret = security_kernel_post_read_file (file , * buf , i_size , id );
110
+ ret = security_kernel_post_read_file (file , * buf , i_size , id );
111
+ }
83
112
84
113
out_free :
85
114
if (ret < 0 ) {
@@ -91,11 +120,11 @@ int kernel_read_file(struct file *file, void **buf,
91
120
92
121
out :
93
122
allow_write_access (file );
94
- return ret == 0 ? pos : ret ;
123
+ return ret == 0 ? copied : ret ;
95
124
}
96
125
EXPORT_SYMBOL_GPL (kernel_read_file );
97
126
98
- int kernel_read_file_from_path (const char * path , void * * buf ,
127
+ int kernel_read_file_from_path (const char * path , loff_t offset , void * * buf ,
99
128
size_t buf_size , size_t * file_size ,
100
129
enum kernel_read_file_id id )
101
130
{
@@ -109,14 +138,15 @@ int kernel_read_file_from_path(const char *path, void **buf,
109
138
if (IS_ERR (file ))
110
139
return PTR_ERR (file );
111
140
112
- ret = kernel_read_file (file , buf , buf_size , file_size , id );
141
+ ret = kernel_read_file (file , offset , buf , buf_size , file_size , id );
113
142
fput (file );
114
143
return ret ;
115
144
}
116
145
EXPORT_SYMBOL_GPL (kernel_read_file_from_path );
117
146
118
- int kernel_read_file_from_path_initns (const char * path , void * * buf ,
119
- size_t buf_size , size_t * file_size ,
147
+ int kernel_read_file_from_path_initns (const char * path , loff_t offset ,
148
+ void * * buf , size_t buf_size ,
149
+ size_t * file_size ,
120
150
enum kernel_read_file_id id )
121
151
{
122
152
struct file * file ;
@@ -135,14 +165,14 @@ int kernel_read_file_from_path_initns(const char *path, void **buf,
135
165
if (IS_ERR (file ))
136
166
return PTR_ERR (file );
137
167
138
- ret = kernel_read_file (file , buf , buf_size , file_size , id );
168
+ ret = kernel_read_file (file , offset , buf , buf_size , file_size , id );
139
169
fput (file );
140
170
return ret ;
141
171
}
142
172
EXPORT_SYMBOL_GPL (kernel_read_file_from_path_initns );
143
173
144
- int kernel_read_file_from_fd (int fd , void * * buf , size_t buf_size ,
145
- size_t * file_size ,
174
+ int kernel_read_file_from_fd (int fd , loff_t offset , void * * buf ,
175
+ size_t buf_size , size_t * file_size ,
146
176
enum kernel_read_file_id id )
147
177
{
148
178
struct fd f = fdget (fd );
@@ -151,7 +181,7 @@ int kernel_read_file_from_fd(int fd, void **buf, size_t buf_size,
151
181
if (!f .file )
152
182
goto out ;
153
183
154
- ret = kernel_read_file (f .file , buf , buf_size , file_size , id );
184
+ ret = kernel_read_file (f .file , offset , buf , buf_size , file_size , id );
155
185
out :
156
186
fdput (f );
157
187
return ret ;
0 commit comments