1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/syscalls.h>
3 #include <linux/export.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>
14 static int flags_by_mnt(int mnt_flags
)
18 if (mnt_flags
& MNT_READONLY
)
20 if (mnt_flags
& MNT_NOSUID
)
22 if (mnt_flags
& MNT_NODEV
)
24 if (mnt_flags
& MNT_NOEXEC
)
26 if (mnt_flags
& MNT_NOATIME
)
28 if (mnt_flags
& MNT_NODIRATIME
)
29 flags
|= ST_NODIRATIME
;
30 if (mnt_flags
& MNT_RELATIME
)
35 static int flags_by_sb(int s_flags
)
38 if (s_flags
& SB_SYNCHRONOUS
)
39 flags
|= ST_SYNCHRONOUS
;
40 if (s_flags
& SB_MANDLOCK
)
42 if (s_flags
& SB_RDONLY
)
47 static int calculate_f_flags(struct vfsmount
*mnt
)
49 return ST_VALID
| flags_by_mnt(mnt
->mnt_flags
) |
50 flags_by_sb(mnt
->mnt_sb
->s_flags
);
53 static int statfs_by_dentry(struct dentry
*dentry
, struct kstatfs
*buf
)
57 if (!dentry
->d_sb
->s_op
->statfs
)
60 memset(buf
, 0, sizeof(*buf
));
61 retval
= security_sb_statfs(dentry
);
64 retval
= dentry
->d_sb
->s_op
->statfs(dentry
, buf
);
65 if (retval
== 0 && buf
->f_frsize
== 0)
66 buf
->f_frsize
= buf
->f_bsize
;
70 int vfs_get_fsid(struct dentry
*dentry
, __kernel_fsid_t
*fsid
)
75 error
= statfs_by_dentry(dentry
, &st
);
82 EXPORT_SYMBOL(vfs_get_fsid
);
84 int vfs_statfs(const struct path
*path
, struct kstatfs
*buf
)
88 error
= statfs_by_dentry(path
->dentry
, buf
);
90 buf
->f_flags
= calculate_f_flags(path
->mnt
);
93 EXPORT_SYMBOL(vfs_statfs
);
95 int user_statfs(const char __user
*pathname
, struct kstatfs
*st
)
99 unsigned int lookup_flags
= LOOKUP_FOLLOW
|LOOKUP_AUTOMOUNT
;
101 error
= user_path_at(AT_FDCWD
, pathname
, lookup_flags
, &path
);
103 error
= vfs_statfs(&path
, st
);
105 if (retry_estale(error
, lookup_flags
)) {
106 lookup_flags
|= LOOKUP_REVAL
;
113 int fd_statfs(int fd
, struct kstatfs
*st
)
115 struct fd f
= fdget_raw(fd
);
118 error
= vfs_statfs(&f
.file
->f_path
, st
);
124 static int do_statfs_native(struct kstatfs
*st
, struct statfs __user
*p
)
128 if (sizeof(buf
) == sizeof(*st
))
129 memcpy(&buf
, st
, sizeof(*st
));
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
)
137 * f_files and f_ffree may be -1; it's okay to stuff
140 if (st
->f_files
!= -1 &&
141 (st
->f_files
& 0xffffffff00000000ULL
))
143 if (st
->f_ffree
!= -1 &&
144 (st
->f_ffree
& 0xffffffff00000000ULL
))
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
));
161 if (copy_to_user(p
, &buf
, sizeof(buf
)))
166 static int do_statfs64(struct kstatfs
*st
, struct statfs64 __user
*p
)
169 if (sizeof(buf
) == sizeof(*st
))
170 memcpy(&buf
, st
, sizeof(*st
));
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
));
185 if (copy_to_user(p
, &buf
, sizeof(buf
)))
190 SYSCALL_DEFINE2(statfs
, const char __user
*, pathname
, struct statfs __user
*, buf
)
193 int error
= user_statfs(pathname
, &st
);
195 error
= do_statfs_native(&st
, buf
);
199 SYSCALL_DEFINE3(statfs64
, const char __user
*, pathname
, size_t, sz
, struct statfs64 __user
*, buf
)
203 if (sz
!= sizeof(*buf
))
205 error
= user_statfs(pathname
, &st
);
207 error
= do_statfs64(&st
, buf
);
211 SYSCALL_DEFINE2(fstatfs
, unsigned int, fd
, struct statfs __user
*, buf
)
214 int error
= fd_statfs(fd
, &st
);
216 error
= do_statfs_native(&st
, buf
);
220 SYSCALL_DEFINE3(fstatfs64
, unsigned int, fd
, size_t, sz
, struct statfs64 __user
*, buf
)
225 if (sz
!= sizeof(*buf
))
228 error
= fd_statfs(fd
, &st
);
230 error
= do_statfs64(&st
, buf
);
234 static int vfs_ustat(dev_t dev
, struct kstatfs
*sbuf
)
236 struct super_block
*s
= user_get_super(dev
);
241 err
= statfs_by_dentry(s
->s_root
, sbuf
);
246 SYSCALL_DEFINE2(ustat
, unsigned, dev
, struct ustat __user
*, ubuf
)
250 int err
= vfs_ustat(new_decode_dev(dev
), &sbuf
);
254 memset(&tmp
,0,sizeof(struct ustat
));
255 tmp
.f_tfree
= sbuf
.f_bfree
;
256 tmp
.f_tinode
= sbuf
.f_ffree
;
258 return copy_to_user(ubuf
, &tmp
, sizeof(struct ustat
)) ? -EFAULT
: 0;
262 static int put_compat_statfs(struct compat_statfs __user
*ubuf
, struct kstatfs
*kbuf
)
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
)
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
))
274 if (kbuf
->f_ffree
!= 0xffffffffffffffffULL
275 && (kbuf
->f_ffree
& 0xffffffff00000000ULL
))
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
)))
297 * The following statfs calls are copies of code from fs/statfs.c and
298 * should be checked against those from time to time
300 COMPAT_SYSCALL_DEFINE2(statfs
, const char __user
*, pathname
, struct compat_statfs __user
*, buf
)
303 int error
= user_statfs(pathname
, &tmp
);
305 error
= put_compat_statfs(buf
, &tmp
);
309 COMPAT_SYSCALL_DEFINE2(fstatfs
, unsigned int, fd
, struct compat_statfs __user
*, buf
)
312 int error
= fd_statfs(fd
, &tmp
);
314 error
= put_compat_statfs(buf
, &tmp
);
318 static int put_compat_statfs64(struct compat_statfs64 __user
*ubuf
, struct kstatfs
*kbuf
)
320 struct compat_statfs64 buf
;
321 if (sizeof(ubuf
->f_bsize
) == 4) {
322 if ((kbuf
->f_type
| kbuf
->f_bsize
| kbuf
->f_namelen
|
323 kbuf
->f_frsize
| kbuf
->f_flags
) & 0xffffffff00000000ULL
)
325 /* f_files and f_ffree may be -1; it's okay
326 * to stuff that into 32 bits */
327 if (kbuf
->f_files
!= 0xffffffffffffffffULL
328 && (kbuf
->f_files
& 0xffffffff00000000ULL
))
330 if (kbuf
->f_ffree
!= 0xffffffffffffffffULL
331 && (kbuf
->f_ffree
& 0xffffffff00000000ULL
))
334 memset(&buf
, 0, sizeof(struct compat_statfs64
));
335 buf
.f_type
= kbuf
->f_type
;
336 buf
.f_bsize
= kbuf
->f_bsize
;
337 buf
.f_blocks
= kbuf
->f_blocks
;
338 buf
.f_bfree
= kbuf
->f_bfree
;
339 buf
.f_bavail
= kbuf
->f_bavail
;
340 buf
.f_files
= kbuf
->f_files
;
341 buf
.f_ffree
= kbuf
->f_ffree
;
342 buf
.f_namelen
= kbuf
->f_namelen
;
343 buf
.f_fsid
.val
[0] = kbuf
->f_fsid
.val
[0];
344 buf
.f_fsid
.val
[1] = kbuf
->f_fsid
.val
[1];
345 buf
.f_frsize
= kbuf
->f_frsize
;
346 buf
.f_flags
= kbuf
->f_flags
;
347 if (copy_to_user(ubuf
, &buf
, sizeof(struct compat_statfs64
)))
352 int kcompat_sys_statfs64(const char __user
* pathname
, compat_size_t sz
, struct compat_statfs64 __user
* buf
)
357 if (sz
!= sizeof(*buf
))
360 error
= user_statfs(pathname
, &tmp
);
362 error
= put_compat_statfs64(buf
, &tmp
);
366 COMPAT_SYSCALL_DEFINE3(statfs64
, const char __user
*, pathname
, compat_size_t
, sz
, struct compat_statfs64 __user
*, buf
)
368 return kcompat_sys_statfs64(pathname
, sz
, buf
);
371 int kcompat_sys_fstatfs64(unsigned int fd
, compat_size_t sz
, struct compat_statfs64 __user
* buf
)
376 if (sz
!= sizeof(*buf
))
379 error
= fd_statfs(fd
, &tmp
);
381 error
= put_compat_statfs64(buf
, &tmp
);
385 COMPAT_SYSCALL_DEFINE3(fstatfs64
, unsigned int, fd
, compat_size_t
, sz
, struct compat_statfs64 __user
*, buf
)
387 return kcompat_sys_fstatfs64(fd
, sz
, buf
);
391 * This is a copy of sys_ustat, just dealing with a structure layout.
392 * Given how simple this syscall is that apporach is more maintainable
393 * than the various conversion hacks.
395 COMPAT_SYSCALL_DEFINE2(ustat
, unsigned, dev
, struct compat_ustat __user
*, u
)
397 struct compat_ustat tmp
;
399 int err
= vfs_ustat(new_decode_dev(dev
), &sbuf
);
403 memset(&tmp
, 0, sizeof(struct compat_ustat
));
404 tmp
.f_tfree
= sbuf
.f_bfree
;
405 tmp
.f_tinode
= sbuf
.f_ffree
;
406 if (copy_to_user(u
, &tmp
, sizeof(struct compat_ustat
)))