Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0
2 : : #include <linux/syscalls.h>
3 : : #include <linux/export.h>
4 : : #include <linux/fs.h>
5 : : #include <linux/file.h>
6 : : #include <linux/mount.h>
7 : : #include <linux/namei.h>
8 : : #include <linux/statfs.h>
9 : : #include <linux/security.h>
10 : : #include <linux/uaccess.h>
11 : : #include <linux/compat.h>
12 : : #include "internal.h"
13 : :
14 : 24976 : static int flags_by_mnt(int mnt_flags)
15 : : {
16 : 24976 : int flags = 0;
17 : :
18 [ + + ]: 24976 : if (mnt_flags & MNT_READONLY)
19 : 112 : flags |= ST_RDONLY;
20 [ + + ]: 24976 : if (mnt_flags & MNT_NOSUID)
21 : 4228 : flags |= ST_NOSUID;
22 [ + + ]: 24976 : if (mnt_flags & MNT_NODEV)
23 : 4228 : flags |= ST_NODEV;
24 [ + + ]: 24976 : if (mnt_flags & MNT_NOEXEC)
25 : 1204 : flags |= ST_NOEXEC;
26 [ - + ]: 24976 : if (mnt_flags & MNT_NOATIME)
27 : 0 : flags |= ST_NOATIME;
28 [ - + ]: 24976 : if (mnt_flags & MNT_NODIRATIME)
29 : 0 : flags |= ST_NODIRATIME;
30 [ + + ]: 24976 : if (mnt_flags & MNT_RELATIME)
31 : 21784 : flags |= ST_RELATIME;
32 : 24976 : return flags;
33 : : }
34 : :
35 : : static int flags_by_sb(int s_flags)
36 : : {
37 : : int flags = 0;
38 : : if (s_flags & SB_SYNCHRONOUS)
39 : : flags |= ST_SYNCHRONOUS;
40 : : if (s_flags & SB_MANDLOCK)
41 : : flags |= ST_MANDLOCK;
42 : : if (s_flags & SB_RDONLY)
43 : : flags |= ST_RDONLY;
44 : : return flags;
45 : : }
46 : :
47 : : static int calculate_f_flags(struct vfsmount *mnt)
48 : : {
49 : : return ST_VALID | flags_by_mnt(mnt->mnt_flags) |
50 : : flags_by_sb(mnt->mnt_sb->s_flags);
51 : : }
52 : :
53 : 24976 : static int statfs_by_dentry(struct dentry *dentry, struct kstatfs *buf)
54 : : {
55 : 24976 : int retval;
56 : :
57 [ + - ]: 24976 : if (!dentry->d_sb->s_op->statfs)
58 : : return -ENOSYS;
59 : :
60 : 24976 : memset(buf, 0, sizeof(*buf));
61 : 24976 : retval = security_sb_statfs(dentry);
62 [ + - ]: 24976 : if (retval)
63 : : return retval;
64 : 24976 : retval = dentry->d_sb->s_op->statfs(dentry, buf);
65 [ + - + - ]: 24976 : if (retval == 0 && buf->f_frsize == 0)
66 : 24976 : buf->f_frsize = buf->f_bsize;
67 : : return retval;
68 : : }
69 : :
70 : 0 : int vfs_get_fsid(struct dentry *dentry, __kernel_fsid_t *fsid)
71 : : {
72 : 0 : struct kstatfs st;
73 : 0 : int error;
74 : :
75 : 0 : error = statfs_by_dentry(dentry, &st);
76 [ # # ]: 0 : if (error)
77 : : return error;
78 : :
79 : 0 : *fsid = st.f_fsid;
80 : 0 : return 0;
81 : : }
82 : : EXPORT_SYMBOL(vfs_get_fsid);
83 : :
84 : 24976 : int vfs_statfs(const struct path *path, struct kstatfs *buf)
85 : : {
86 : 24976 : int error;
87 : :
88 : 24976 : error = statfs_by_dentry(path->dentry, buf);
89 [ + - ]: 24976 : if (!error)
90 : 24976 : buf->f_flags = calculate_f_flags(path->mnt);
91 : 24976 : return error;
92 : : }
93 : : EXPORT_SYMBOL(vfs_statfs);
94 : :
95 : 17528 : int user_statfs(const char __user *pathname, struct kstatfs *st)
96 : : {
97 : 17528 : struct path path;
98 : 17528 : int error;
99 : 17528 : unsigned int lookup_flags = LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT;
100 : 17528 : retry:
101 : 17528 : error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
102 [ + + ]: 17528 : if (!error) {
103 : 17416 : error = vfs_statfs(&path, st);
104 : 17416 : path_put(&path);
105 [ - + - + ]: 34832 : if (retry_estale(error, lookup_flags)) {
106 : 0 : lookup_flags |= LOOKUP_REVAL;
107 : 0 : goto retry;
108 : : }
109 : : }
110 : 17528 : return error;
111 : : }
112 : :
113 : 7560 : int fd_statfs(int fd, struct kstatfs *st)
114 : : {
115 : 7560 : struct fd f = fdget_raw(fd);
116 : 7560 : int error = -EBADF;
117 [ + - ]: 7560 : if (f.file) {
118 : 7560 : error = vfs_statfs(&f.file->f_path, st);
119 [ - + ]: 7560 : fdput(f);
120 : : }
121 : 7560 : return error;
122 : : }
123 : :
124 : 24976 : static int do_statfs_native(struct kstatfs *st, struct statfs __user *p)
125 : : {
126 : 24976 : struct statfs buf;
127 : :
128 : 24976 : if (sizeof(buf) == sizeof(*st))
129 : 24976 : memcpy(&buf, st, sizeof(*st));
130 : : else {
131 : : if (sizeof buf.f_blocks == 4) {
132 : : if ((st->f_blocks | st->f_bfree | st->f_bavail |
133 : : st->f_bsize | st->f_frsize) &
134 : : 0xffffffff00000000ULL)
135 : : return -EOVERFLOW;
136 : : /*
137 : : * f_files and f_ffree may be -1; it's okay to stuff
138 : : * that into 32 bits
139 : : */
140 : : if (st->f_files != -1 &&
141 : : (st->f_files & 0xffffffff00000000ULL))
142 : : return -EOVERFLOW;
143 : : if (st->f_ffree != -1 &&
144 : : (st->f_ffree & 0xffffffff00000000ULL))
145 : : return -EOVERFLOW;
146 : : }
147 : :
148 : : buf.f_type = st->f_type;
149 : : buf.f_bsize = st->f_bsize;
150 : : buf.f_blocks = st->f_blocks;
151 : : buf.f_bfree = st->f_bfree;
152 : : buf.f_bavail = st->f_bavail;
153 : : buf.f_files = st->f_files;
154 : : buf.f_ffree = st->f_ffree;
155 : : buf.f_fsid = st->f_fsid;
156 : : buf.f_namelen = st->f_namelen;
157 : : buf.f_frsize = st->f_frsize;
158 : : buf.f_flags = st->f_flags;
159 : : memset(buf.f_spare, 0, sizeof(buf.f_spare));
160 : : }
161 [ - + ]: 24976 : if (copy_to_user(p, &buf, sizeof(buf)))
162 : 0 : return -EFAULT;
163 : : return 0;
164 : : }
165 : :
166 : 0 : static int do_statfs64(struct kstatfs *st, struct statfs64 __user *p)
167 : : {
168 : 0 : struct statfs64 buf;
169 : 0 : if (sizeof(buf) == sizeof(*st))
170 : 0 : memcpy(&buf, st, sizeof(*st));
171 : : else {
172 : : buf.f_type = st->f_type;
173 : : buf.f_bsize = st->f_bsize;
174 : : buf.f_blocks = st->f_blocks;
175 : : buf.f_bfree = st->f_bfree;
176 : : buf.f_bavail = st->f_bavail;
177 : : buf.f_files = st->f_files;
178 : : buf.f_ffree = st->f_ffree;
179 : : buf.f_fsid = st->f_fsid;
180 : : buf.f_namelen = st->f_namelen;
181 : : buf.f_frsize = st->f_frsize;
182 : : buf.f_flags = st->f_flags;
183 : : memset(buf.f_spare, 0, sizeof(buf.f_spare));
184 : : }
185 [ # # ]: 0 : if (copy_to_user(p, &buf, sizeof(buf)))
186 : 0 : return -EFAULT;
187 : : return 0;
188 : : }
189 : :
190 : 35056 : SYSCALL_DEFINE2(statfs, const char __user *, pathname, struct statfs __user *, buf)
191 : : {
192 : 17528 : struct kstatfs st;
193 : 17528 : int error = user_statfs(pathname, &st);
194 [ + + ]: 17528 : if (!error)
195 : 17416 : error = do_statfs_native(&st, buf);
196 : 17528 : return error;
197 : : }
198 : :
199 : 0 : SYSCALL_DEFINE3(statfs64, const char __user *, pathname, size_t, sz, struct statfs64 __user *, buf)
200 : : {
201 : 0 : struct kstatfs st;
202 : 0 : int error;
203 [ # # ]: 0 : if (sz != sizeof(*buf))
204 : : return -EINVAL;
205 : 0 : error = user_statfs(pathname, &st);
206 [ # # ]: 0 : if (!error)
207 : 0 : error = do_statfs64(&st, buf);
208 : 0 : return error;
209 : : }
210 : :
211 : 15120 : SYSCALL_DEFINE2(fstatfs, unsigned int, fd, struct statfs __user *, buf)
212 : : {
213 : 7560 : struct kstatfs st;
214 : 7560 : int error = fd_statfs(fd, &st);
215 [ + - ]: 7560 : if (!error)
216 : 7560 : error = do_statfs_native(&st, buf);
217 : 7560 : return error;
218 : : }
219 : :
220 : 0 : SYSCALL_DEFINE3(fstatfs64, unsigned int, fd, size_t, sz, struct statfs64 __user *, buf)
221 : : {
222 : 0 : struct kstatfs st;
223 : 0 : int error;
224 : :
225 [ # # ]: 0 : if (sz != sizeof(*buf))
226 : : return -EINVAL;
227 : :
228 : 0 : error = fd_statfs(fd, &st);
229 [ # # ]: 0 : if (!error)
230 : 0 : error = do_statfs64(&st, buf);
231 : 0 : return error;
232 : : }
233 : :
234 : 0 : static int vfs_ustat(dev_t dev, struct kstatfs *sbuf)
235 : : {
236 : 0 : struct super_block *s = user_get_super(dev);
237 : 0 : int err;
238 [ # # ]: 0 : if (!s)
239 : : return -EINVAL;
240 : :
241 : 0 : err = statfs_by_dentry(s->s_root, sbuf);
242 : 0 : drop_super(s);
243 : 0 : return err;
244 : : }
245 : :
246 : 0 : SYSCALL_DEFINE2(ustat, unsigned, dev, struct ustat __user *, ubuf)
247 : : {
248 : 0 : struct ustat tmp;
249 : 0 : struct kstatfs sbuf;
250 : 0 : int err = vfs_ustat(new_decode_dev(dev), &sbuf);
251 [ # # ]: 0 : if (err)
252 : 0 : return err;
253 : :
254 : 0 : memset(&tmp,0,sizeof(struct ustat));
255 : 0 : tmp.f_tfree = sbuf.f_bfree;
256 : 0 : tmp.f_tinode = sbuf.f_ffree;
257 : :
258 [ # # ]: 0 : return copy_to_user(ubuf, &tmp, sizeof(struct ustat)) ? -EFAULT : 0;
259 : : }
260 : :
261 : : #ifdef CONFIG_COMPAT
262 : 0 : static int put_compat_statfs(struct compat_statfs __user *ubuf, struct kstatfs *kbuf)
263 : : {
264 : 0 : struct compat_statfs buf;
265 : 0 : if (sizeof ubuf->f_blocks == 4) {
266 : 0 : if ((kbuf->f_blocks | kbuf->f_bfree | kbuf->f_bavail |
267 [ # # ]: 0 : kbuf->f_bsize | kbuf->f_frsize) & 0xffffffff00000000ULL)
268 : : return -EOVERFLOW;
269 : : /* f_files and f_ffree may be -1; it's okay
270 : : * to stuff that into 32 bits */
271 [ # # ]: 0 : if (kbuf->f_files != 0xffffffffffffffffULL
272 [ # # ]: 0 : && (kbuf->f_files & 0xffffffff00000000ULL))
273 : : return -EOVERFLOW;
274 [ # # ]: 0 : if (kbuf->f_ffree != 0xffffffffffffffffULL
275 [ # # ]: 0 : && (kbuf->f_ffree & 0xffffffff00000000ULL))
276 : : return -EOVERFLOW;
277 : : }
278 : 0 : memset(&buf, 0, sizeof(struct compat_statfs));
279 : 0 : buf.f_type = kbuf->f_type;
280 : 0 : buf.f_bsize = kbuf->f_bsize;
281 : 0 : buf.f_blocks = kbuf->f_blocks;
282 : 0 : buf.f_bfree = kbuf->f_bfree;
283 : 0 : buf.f_bavail = kbuf->f_bavail;
284 : 0 : buf.f_files = kbuf->f_files;
285 : 0 : buf.f_ffree = kbuf->f_ffree;
286 : 0 : buf.f_namelen = kbuf->f_namelen;
287 : 0 : buf.f_fsid.val[0] = kbuf->f_fsid.val[0];
288 : 0 : buf.f_fsid.val[1] = kbuf->f_fsid.val[1];
289 : 0 : buf.f_frsize = kbuf->f_frsize;
290 : 0 : buf.f_flags = kbuf->f_flags;
291 [ # # ]: 0 : if (copy_to_user(ubuf, &buf, sizeof(struct compat_statfs)))
292 : 0 : return -EFAULT;
293 : : return 0;
294 : : }
295 : :
296 : : /*
297 : : * The following statfs calls are copies of code from fs/statfs.c and
298 : : * should be checked against those from time to time
299 : : */
300 : 0 : COMPAT_SYSCALL_DEFINE2(statfs, const char __user *, pathname, struct compat_statfs __user *, buf)
301 : : {
302 : 0 : struct kstatfs tmp;
303 : 0 : int error = user_statfs(pathname, &tmp);
304 [ # # ]: 0 : if (!error)
305 : 0 : error = put_compat_statfs(buf, &tmp);
306 : 0 : return error;
307 : : }
308 : :
309 : 0 : COMPAT_SYSCALL_DEFINE2(fstatfs, unsigned int, fd, struct compat_statfs __user *, buf)
310 : : {
311 : 0 : struct kstatfs tmp;
312 : 0 : int error = fd_statfs(fd, &tmp);
313 [ # # ]: 0 : if (!error)
314 : 0 : error = put_compat_statfs(buf, &tmp);
315 : 0 : return error;
316 : : }
317 : :
318 : 0 : static int put_compat_statfs64(struct compat_statfs64 __user *ubuf, struct kstatfs *kbuf)
319 : : {
320 : 0 : struct compat_statfs64 buf;
321 : :
322 [ # # ]: 0 : if ((kbuf->f_bsize | kbuf->f_frsize) & 0xffffffff00000000ULL)
323 : : return -EOVERFLOW;
324 : :
325 : 0 : memset(&buf, 0, sizeof(struct compat_statfs64));
326 : 0 : buf.f_type = kbuf->f_type;
327 : 0 : buf.f_bsize = kbuf->f_bsize;
328 : 0 : buf.f_blocks = kbuf->f_blocks;
329 : 0 : buf.f_bfree = kbuf->f_bfree;
330 : 0 : buf.f_bavail = kbuf->f_bavail;
331 : 0 : buf.f_files = kbuf->f_files;
332 : 0 : buf.f_ffree = kbuf->f_ffree;
333 : 0 : buf.f_namelen = kbuf->f_namelen;
334 : 0 : buf.f_fsid.val[0] = kbuf->f_fsid.val[0];
335 : 0 : buf.f_fsid.val[1] = kbuf->f_fsid.val[1];
336 : 0 : buf.f_frsize = kbuf->f_frsize;
337 : 0 : buf.f_flags = kbuf->f_flags;
338 [ # # ]: 0 : if (copy_to_user(ubuf, &buf, sizeof(struct compat_statfs64)))
339 : 0 : return -EFAULT;
340 : : return 0;
341 : : }
342 : :
343 : 0 : int kcompat_sys_statfs64(const char __user * pathname, compat_size_t sz, struct compat_statfs64 __user * buf)
344 : : {
345 : 0 : struct kstatfs tmp;
346 : 0 : int error;
347 : :
348 [ # # ]: 0 : if (sz != sizeof(*buf))
349 : : return -EINVAL;
350 : :
351 : 0 : error = user_statfs(pathname, &tmp);
352 [ # # ]: 0 : if (!error)
353 : 0 : error = put_compat_statfs64(buf, &tmp);
354 : : return error;
355 : : }
356 : :
357 : 0 : COMPAT_SYSCALL_DEFINE3(statfs64, const char __user *, pathname, compat_size_t, sz, struct compat_statfs64 __user *, buf)
358 : : {
359 : 0 : return kcompat_sys_statfs64(pathname, sz, buf);
360 : : }
361 : :
362 : 0 : int kcompat_sys_fstatfs64(unsigned int fd, compat_size_t sz, struct compat_statfs64 __user * buf)
363 : : {
364 : 0 : struct kstatfs tmp;
365 : 0 : int error;
366 : :
367 [ # # ]: 0 : if (sz != sizeof(*buf))
368 : : return -EINVAL;
369 : :
370 : 0 : error = fd_statfs(fd, &tmp);
371 [ # # ]: 0 : if (!error)
372 : 0 : error = put_compat_statfs64(buf, &tmp);
373 : : return error;
374 : : }
375 : :
376 : 0 : COMPAT_SYSCALL_DEFINE3(fstatfs64, unsigned int, fd, compat_size_t, sz, struct compat_statfs64 __user *, buf)
377 : : {
378 : 0 : return kcompat_sys_fstatfs64(fd, sz, buf);
379 : : }
380 : :
381 : : /*
382 : : * This is a copy of sys_ustat, just dealing with a structure layout.
383 : : * Given how simple this syscall is that apporach is more maintainable
384 : : * than the various conversion hacks.
385 : : */
386 : 0 : COMPAT_SYSCALL_DEFINE2(ustat, unsigned, dev, struct compat_ustat __user *, u)
387 : : {
388 : 0 : struct compat_ustat tmp;
389 : 0 : struct kstatfs sbuf;
390 : 0 : int err = vfs_ustat(new_decode_dev(dev), &sbuf);
391 [ # # ]: 0 : if (err)
392 : 0 : return err;
393 : :
394 : 0 : memset(&tmp, 0, sizeof(struct compat_ustat));
395 : 0 : tmp.f_tfree = sbuf.f_bfree;
396 : 0 : tmp.f_tinode = sbuf.f_ffree;
397 [ # # ]: 0 : if (copy_to_user(u, &tmp, sizeof(struct compat_ustat)))
398 : 0 : return -EFAULT;
399 : : return 0;
400 : : }
401 : : #endif
|