LCOV - code coverage report
Current view: top level - fs - statfs.c (source / functions) Hit Total Coverage
Test: fstests of 6.5.0-rc4-xfsa @ Mon Jul 31 20:08:27 PDT 2023 Lines: 80 131 61.1 %
Date: 2023-07-31 20:08:27 Functions: 12 21 57.1 %

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

Generated by: LCOV version 1.14