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 : 3 : static int flags_by_mnt(int mnt_flags)
15 : : {
16 : : int flags = 0;
17 : :
18 : 3 : if (mnt_flags & MNT_READONLY)
19 : : flags |= ST_RDONLY;
20 : 3 : if (mnt_flags & MNT_NOSUID)
21 : 3 : flags |= ST_NOSUID;
22 : 3 : if (mnt_flags & MNT_NODEV)
23 : 3 : flags |= ST_NODEV;
24 : 3 : if (mnt_flags & MNT_NOEXEC)
25 : 3 : flags |= ST_NOEXEC;
26 : 3 : if (mnt_flags & MNT_NOATIME)
27 : 3 : flags |= ST_NOATIME;
28 : 3 : if (mnt_flags & MNT_NODIRATIME)
29 : 0 : flags |= ST_NODIRATIME;
30 : 3 : if (mnt_flags & MNT_RELATIME)
31 : 3 : flags |= ST_RELATIME;
32 : 3 : return flags;
33 : : }
34 : :
35 : : static int flags_by_sb(int s_flags)
36 : : {
37 : : int flags = 0;
38 : 3 : if (s_flags & SB_SYNCHRONOUS)
39 : : flags |= ST_SYNCHRONOUS;
40 : 3 : if (s_flags & SB_MANDLOCK)
41 : 0 : flags |= ST_MANDLOCK;
42 : 3 : if (s_flags & SB_RDONLY)
43 : 3 : flags |= ST_RDONLY;
44 : : return flags;
45 : : }
46 : :
47 : 3 : static int calculate_f_flags(struct vfsmount *mnt)
48 : : {
49 : 3 : return ST_VALID | flags_by_mnt(mnt->mnt_flags) |
50 : 3 : flags_by_sb(mnt->mnt_sb->s_flags);
51 : : }
52 : :
53 : 3 : static int statfs_by_dentry(struct dentry *dentry, struct kstatfs *buf)
54 : : {
55 : : int retval;
56 : :
57 : 3 : if (!dentry->d_sb->s_op->statfs)
58 : : return -ENOSYS;
59 : :
60 : 3 : memset(buf, 0, sizeof(*buf));
61 : 3 : retval = security_sb_statfs(dentry);
62 : 3 : if (retval)
63 : : return retval;
64 : 3 : retval = dentry->d_sb->s_op->statfs(dentry, buf);
65 : 3 : if (retval == 0 && buf->f_frsize == 0)
66 : 3 : buf->f_frsize = buf->f_bsize;
67 : 3 : return retval;
68 : : }
69 : :
70 : 0 : int vfs_get_fsid(struct dentry *dentry, __kernel_fsid_t *fsid)
71 : : {
72 : : struct kstatfs st;
73 : : 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 : 3 : int vfs_statfs(const struct path *path, struct kstatfs *buf)
85 : : {
86 : : int error;
87 : :
88 : 3 : error = statfs_by_dentry(path->dentry, buf);
89 : 3 : if (!error)
90 : 3 : buf->f_flags = calculate_f_flags(path->mnt);
91 : 3 : return error;
92 : : }
93 : : EXPORT_SYMBOL(vfs_statfs);
94 : :
95 : 3 : int user_statfs(const char __user *pathname, struct kstatfs *st)
96 : : {
97 : : struct path path;
98 : : int error;
99 : : unsigned int lookup_flags = LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT;
100 : : retry:
101 : : error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
102 : 3 : if (!error) {
103 : 3 : error = vfs_statfs(&path, st);
104 : 3 : path_put(&path);
105 : 3 : if (retry_estale(error, lookup_flags)) {
106 : : lookup_flags |= LOOKUP_REVAL;
107 : : goto retry;
108 : : }
109 : : }
110 : 3 : return error;
111 : : }
112 : :
113 : 3 : int fd_statfs(int fd, struct kstatfs *st)
114 : : {
115 : 3 : struct fd f = fdget_raw(fd);
116 : : int error = -EBADF;
117 : 3 : if (f.file) {
118 : 3 : error = vfs_statfs(&f.file->f_path, st);
119 : : fdput(f);
120 : : }
121 : 3 : return error;
122 : : }
123 : :
124 : 3 : static int do_statfs_native(struct kstatfs *st, struct statfs __user *p)
125 : : {
126 : : struct statfs buf;
127 : :
128 : : if (sizeof(buf) == sizeof(*st))
129 : : memcpy(&buf, st, sizeof(*st));
130 : : else {
131 : : if (sizeof buf.f_blocks == 4) {
132 : 3 : if ((st->f_blocks | st->f_bfree | st->f_bavail |
133 : 3 : 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 : 3 : if (st->f_files != -1 &&
141 : 3 : (st->f_files & 0xffffffff00000000ULL))
142 : : return -EOVERFLOW;
143 : 3 : if (st->f_ffree != -1 &&
144 : 3 : (st->f_ffree & 0xffffffff00000000ULL))
145 : : return -EOVERFLOW;
146 : : }
147 : :
148 : 3 : buf.f_type = st->f_type;
149 : 3 : buf.f_bsize = st->f_bsize;
150 : 3 : buf.f_blocks = st->f_blocks;
151 : 3 : buf.f_bfree = st->f_bfree;
152 : 3 : buf.f_bavail = st->f_bavail;
153 : 3 : buf.f_files = st->f_files;
154 : 3 : buf.f_ffree = st->f_ffree;
155 : 3 : buf.f_fsid = st->f_fsid;
156 : 3 : buf.f_namelen = st->f_namelen;
157 : 3 : buf.f_frsize = st->f_frsize;
158 : 3 : buf.f_flags = st->f_flags;
159 : 3 : memset(buf.f_spare, 0, sizeof(buf.f_spare));
160 : : }
161 : 3 : if (copy_to_user(p, &buf, sizeof(buf)))
162 : : return -EFAULT;
163 : 3 : return 0;
164 : : }
165 : :
166 : 3 : static int do_statfs64(struct kstatfs *st, struct statfs64 __user *p)
167 : : {
168 : : struct statfs64 buf;
169 : : if (sizeof(buf) == sizeof(*st))
170 : : memcpy(&buf, st, sizeof(*st));
171 : : else {
172 : 3 : buf.f_type = st->f_type;
173 : 3 : buf.f_bsize = st->f_bsize;
174 : 3 : buf.f_blocks = st->f_blocks;
175 : 3 : buf.f_bfree = st->f_bfree;
176 : 3 : buf.f_bavail = st->f_bavail;
177 : 3 : buf.f_files = st->f_files;
178 : 3 : buf.f_ffree = st->f_ffree;
179 : 3 : buf.f_fsid = st->f_fsid;
180 : 3 : buf.f_namelen = st->f_namelen;
181 : 3 : buf.f_frsize = st->f_frsize;
182 : 3 : buf.f_flags = st->f_flags;
183 : 3 : memset(buf.f_spare, 0, sizeof(buf.f_spare));
184 : : }
185 : 3 : if (copy_to_user(p, &buf, sizeof(buf)))
186 : : return -EFAULT;
187 : 3 : return 0;
188 : : }
189 : :
190 : 3 : SYSCALL_DEFINE2(statfs, const char __user *, pathname, struct statfs __user *, buf)
191 : : {
192 : : struct kstatfs st;
193 : 3 : int error = user_statfs(pathname, &st);
194 : 3 : if (!error)
195 : 3 : error = do_statfs_native(&st, buf);
196 : 3 : return error;
197 : : }
198 : :
199 : 3 : SYSCALL_DEFINE3(statfs64, const char __user *, pathname, size_t, sz, struct statfs64 __user *, buf)
200 : : {
201 : : struct kstatfs st;
202 : : int error;
203 : 3 : if (sz != sizeof(*buf))
204 : : return -EINVAL;
205 : 3 : error = user_statfs(pathname, &st);
206 : 3 : if (!error)
207 : 3 : error = do_statfs64(&st, buf);
208 : 3 : return error;
209 : : }
210 : :
211 : 0 : SYSCALL_DEFINE2(fstatfs, unsigned int, fd, struct statfs __user *, buf)
212 : : {
213 : : struct kstatfs st;
214 : 0 : int error = fd_statfs(fd, &st);
215 : 0 : if (!error)
216 : 0 : error = do_statfs_native(&st, buf);
217 : 0 : return error;
218 : : }
219 : :
220 : 3 : SYSCALL_DEFINE3(fstatfs64, unsigned int, fd, size_t, sz, struct statfs64 __user *, buf)
221 : : {
222 : : struct kstatfs st;
223 : : int error;
224 : :
225 : 3 : if (sz != sizeof(*buf))
226 : : return -EINVAL;
227 : :
228 : 3 : error = fd_statfs(fd, &st);
229 : 3 : if (!error)
230 : 3 : error = do_statfs64(&st, buf);
231 : 3 : 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 : : 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 : : struct ustat tmp;
249 : : struct kstatfs sbuf;
250 : 0 : int err = vfs_ustat(new_decode_dev(dev), &sbuf);
251 : 0 : if (err)
252 : : 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 : : static int put_compat_statfs(struct compat_statfs __user *ubuf, struct kstatfs *kbuf)
263 : : {
264 : : struct compat_statfs buf;
265 : : if (sizeof ubuf->f_blocks == 4) {
266 : : if ((kbuf->f_blocks | kbuf->f_bfree | kbuf->f_bavail |
267 : : 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 : : if (kbuf->f_files != 0xffffffffffffffffULL
272 : : && (kbuf->f_files & 0xffffffff00000000ULL))
273 : : return -EOVERFLOW;
274 : : if (kbuf->f_ffree != 0xffffffffffffffffULL
275 : : && (kbuf->f_ffree & 0xffffffff00000000ULL))
276 : : return -EOVERFLOW;
277 : : }
278 : : memset(&buf, 0, sizeof(struct compat_statfs));
279 : : buf.f_type = kbuf->f_type;
280 : : buf.f_bsize = kbuf->f_bsize;
281 : : buf.f_blocks = kbuf->f_blocks;
282 : : buf.f_bfree = kbuf->f_bfree;
283 : : buf.f_bavail = kbuf->f_bavail;
284 : : buf.f_files = kbuf->f_files;
285 : : buf.f_ffree = kbuf->f_ffree;
286 : : buf.f_namelen = kbuf->f_namelen;
287 : : buf.f_fsid.val[0] = kbuf->f_fsid.val[0];
288 : : buf.f_fsid.val[1] = kbuf->f_fsid.val[1];
289 : : buf.f_frsize = kbuf->f_frsize;
290 : : buf.f_flags = kbuf->f_flags;
291 : : if (copy_to_user(ubuf, &buf, sizeof(struct compat_statfs)))
292 : : 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 : : COMPAT_SYSCALL_DEFINE2(statfs, const char __user *, pathname, struct compat_statfs __user *, buf)
301 : : {
302 : : struct kstatfs tmp;
303 : : int error = user_statfs(pathname, &tmp);
304 : : if (!error)
305 : : error = put_compat_statfs(buf, &tmp);
306 : : return error;
307 : : }
308 : :
309 : : COMPAT_SYSCALL_DEFINE2(fstatfs, unsigned int, fd, struct compat_statfs __user *, buf)
310 : : {
311 : : struct kstatfs tmp;
312 : : int error = fd_statfs(fd, &tmp);
313 : : if (!error)
314 : : error = put_compat_statfs(buf, &tmp);
315 : : return error;
316 : : }
317 : :
318 : : static int put_compat_statfs64(struct compat_statfs64 __user *ubuf, struct kstatfs *kbuf)
319 : : {
320 : : struct compat_statfs64 buf;
321 : :
322 : : if ((kbuf->f_bsize | kbuf->f_frsize) & 0xffffffff00000000ULL)
323 : : return -EOVERFLOW;
324 : :
325 : : memset(&buf, 0, sizeof(struct compat_statfs64));
326 : : buf.f_type = kbuf->f_type;
327 : : buf.f_bsize = kbuf->f_bsize;
328 : : buf.f_blocks = kbuf->f_blocks;
329 : : buf.f_bfree = kbuf->f_bfree;
330 : : buf.f_bavail = kbuf->f_bavail;
331 : : buf.f_files = kbuf->f_files;
332 : : buf.f_ffree = kbuf->f_ffree;
333 : : buf.f_namelen = kbuf->f_namelen;
334 : : buf.f_fsid.val[0] = kbuf->f_fsid.val[0];
335 : : buf.f_fsid.val[1] = kbuf->f_fsid.val[1];
336 : : buf.f_frsize = kbuf->f_frsize;
337 : : buf.f_flags = kbuf->f_flags;
338 : : if (copy_to_user(ubuf, &buf, sizeof(struct compat_statfs64)))
339 : : return -EFAULT;
340 : : return 0;
341 : : }
342 : :
343 : : int kcompat_sys_statfs64(const char __user * pathname, compat_size_t sz, struct compat_statfs64 __user * buf)
344 : : {
345 : : struct kstatfs tmp;
346 : : int error;
347 : :
348 : : if (sz != sizeof(*buf))
349 : : return -EINVAL;
350 : :
351 : : error = user_statfs(pathname, &tmp);
352 : : if (!error)
353 : : error = put_compat_statfs64(buf, &tmp);
354 : : return error;
355 : : }
356 : :
357 : : COMPAT_SYSCALL_DEFINE3(statfs64, const char __user *, pathname, compat_size_t, sz, struct compat_statfs64 __user *, buf)
358 : : {
359 : : return kcompat_sys_statfs64(pathname, sz, buf);
360 : : }
361 : :
362 : : int kcompat_sys_fstatfs64(unsigned int fd, compat_size_t sz, struct compat_statfs64 __user * buf)
363 : : {
364 : : struct kstatfs tmp;
365 : : int error;
366 : :
367 : : if (sz != sizeof(*buf))
368 : : return -EINVAL;
369 : :
370 : : error = fd_statfs(fd, &tmp);
371 : : if (!error)
372 : : error = put_compat_statfs64(buf, &tmp);
373 : : return error;
374 : : }
375 : :
376 : : COMPAT_SYSCALL_DEFINE3(fstatfs64, unsigned int, fd, compat_size_t, sz, struct compat_statfs64 __user *, buf)
377 : : {
378 : : 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 : : COMPAT_SYSCALL_DEFINE2(ustat, unsigned, dev, struct compat_ustat __user *, u)
387 : : {
388 : : struct compat_ustat tmp;
389 : : struct kstatfs sbuf;
390 : : int err = vfs_ustat(new_decode_dev(dev), &sbuf);
391 : : if (err)
392 : : return err;
393 : :
394 : : memset(&tmp, 0, sizeof(struct compat_ustat));
395 : : tmp.f_tfree = sbuf.f_bfree;
396 : : tmp.f_tinode = sbuf.f_ffree;
397 : : if (copy_to_user(u, &tmp, sizeof(struct compat_ustat)))
398 : : return -EFAULT;
399 : : return 0;
400 : : }
401 : : #endif
|