root/fs/statfs.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. flags_by_mnt
  2. flags_by_sb
  3. calculate_f_flags
  4. statfs_by_dentry
  5. vfs_get_fsid
  6. vfs_statfs
  7. user_statfs
  8. fd_statfs
  9. do_statfs_native
  10. do_statfs64
  11. SYSCALL_DEFINE2
  12. SYSCALL_DEFINE3
  13. SYSCALL_DEFINE2
  14. SYSCALL_DEFINE3
  15. vfs_ustat
  16. SYSCALL_DEFINE2
  17. put_compat_statfs
  18. COMPAT_SYSCALL_DEFINE2
  19. COMPAT_SYSCALL_DEFINE2
  20. put_compat_statfs64
  21. kcompat_sys_statfs64
  22. COMPAT_SYSCALL_DEFINE3
  23. kcompat_sys_fstatfs64
  24. COMPAT_SYSCALL_DEFINE3
  25. COMPAT_SYSCALL_DEFINE2

   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 static int flags_by_mnt(int mnt_flags)
  15 {
  16         int flags = 0;
  17 
  18         if (mnt_flags & MNT_READONLY)
  19                 flags |= ST_RDONLY;
  20         if (mnt_flags & MNT_NOSUID)
  21                 flags |= ST_NOSUID;
  22         if (mnt_flags & MNT_NODEV)
  23                 flags |= ST_NODEV;
  24         if (mnt_flags & MNT_NOEXEC)
  25                 flags |= ST_NOEXEC;
  26         if (mnt_flags & MNT_NOATIME)
  27                 flags |= ST_NOATIME;
  28         if (mnt_flags & MNT_NODIRATIME)
  29                 flags |= ST_NODIRATIME;
  30         if (mnt_flags & MNT_RELATIME)
  31                 flags |= ST_RELATIME;
  32         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 static int statfs_by_dentry(struct dentry *dentry, struct kstatfs *buf)
  54 {
  55         int retval;
  56 
  57         if (!dentry->d_sb->s_op->statfs)
  58                 return -ENOSYS;
  59 
  60         memset(buf, 0, sizeof(*buf));
  61         retval = security_sb_statfs(dentry);
  62         if (retval)
  63                 return retval;
  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;
  67         return retval;
  68 }
  69 
  70 int vfs_get_fsid(struct dentry *dentry, __kernel_fsid_t *fsid)
  71 {
  72         struct kstatfs st;
  73         int error;
  74 
  75         error = statfs_by_dentry(dentry, &st);
  76         if (error)
  77                 return error;
  78 
  79         *fsid = st.f_fsid;
  80         return 0;
  81 }
  82 EXPORT_SYMBOL(vfs_get_fsid);
  83 
  84 int vfs_statfs(const struct path *path, struct kstatfs *buf)
  85 {
  86         int error;
  87 
  88         error = statfs_by_dentry(path->dentry, buf);
  89         if (!error)
  90                 buf->f_flags = calculate_f_flags(path->mnt);
  91         return error;
  92 }
  93 EXPORT_SYMBOL(vfs_statfs);
  94 
  95 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         if (!error) {
 103                 error = vfs_statfs(&path, st);
 104                 path_put(&path);
 105                 if (retry_estale(error, lookup_flags)) {
 106                         lookup_flags |= LOOKUP_REVAL;
 107                         goto retry;
 108                 }
 109         }
 110         return error;
 111 }
 112 
 113 int fd_statfs(int fd, struct kstatfs *st)
 114 {
 115         struct fd f = fdget_raw(fd);
 116         int error = -EBADF;
 117         if (f.file) {
 118                 error = vfs_statfs(&f.file->f_path, st);
 119                 fdput(f);
 120         }
 121         return error;
 122 }
 123 
 124 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                         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         if (copy_to_user(p, &buf, sizeof(buf)))
 162                 return -EFAULT;
 163         return 0;
 164 }
 165 
 166 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                 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         if (copy_to_user(p, &buf, sizeof(buf)))
 186                 return -EFAULT;
 187         return 0;
 188 }
 189 
 190 SYSCALL_DEFINE2(statfs, const char __user *, pathname, struct statfs __user *, buf)
 191 {
 192         struct kstatfs st;
 193         int error = user_statfs(pathname, &st);
 194         if (!error)
 195                 error = do_statfs_native(&st, buf);
 196         return error;
 197 }
 198 
 199 SYSCALL_DEFINE3(statfs64, const char __user *, pathname, size_t, sz, struct statfs64 __user *, buf)
 200 {
 201         struct kstatfs st;
 202         int error;
 203         if (sz != sizeof(*buf))
 204                 return -EINVAL;
 205         error = user_statfs(pathname, &st);
 206         if (!error)
 207                 error = do_statfs64(&st, buf);
 208         return error;
 209 }
 210 
 211 SYSCALL_DEFINE2(fstatfs, unsigned int, fd, struct statfs __user *, buf)
 212 {
 213         struct kstatfs st;
 214         int error = fd_statfs(fd, &st);
 215         if (!error)
 216                 error = do_statfs_native(&st, buf);
 217         return error;
 218 }
 219 
 220 SYSCALL_DEFINE3(fstatfs64, unsigned int, fd, size_t, sz, struct statfs64 __user *, buf)
 221 {
 222         struct kstatfs st;
 223         int error;
 224 
 225         if (sz != sizeof(*buf))
 226                 return -EINVAL;
 227 
 228         error = fd_statfs(fd, &st);
 229         if (!error)
 230                 error = do_statfs64(&st, buf);
 231         return error;
 232 }
 233 
 234 static int vfs_ustat(dev_t dev, struct kstatfs *sbuf)
 235 {
 236         struct super_block *s = user_get_super(dev);
 237         int err;
 238         if (!s)
 239                 return -EINVAL;
 240 
 241         err = statfs_by_dentry(s->s_root, sbuf);
 242         drop_super(s);
 243         return err;
 244 }
 245 
 246 SYSCALL_DEFINE2(ustat, unsigned, dev, struct ustat __user *, ubuf)
 247 {
 248         struct ustat tmp;
 249         struct kstatfs sbuf;
 250         int err = vfs_ustat(new_decode_dev(dev), &sbuf);
 251         if (err)
 252                 return err;
 253 
 254         memset(&tmp,0,sizeof(struct ustat));
 255         tmp.f_tfree = sbuf.f_bfree;
 256         tmp.f_tinode = sbuf.f_ffree;
 257 
 258         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

/* [<][>][^][v][top][bottom][index][help] */