LCOV - code coverage report
Current view: top level - fs - statfs.c (source / functions) Hit Total Coverage
Test: fstests of 6.5.0-rc3-djwx @ Mon Jul 31 20:08:22 PDT 2023 Lines: 81 214 37.9 %
Date: 2023-07-31 20:08:22 Functions: 12 38 31.6 %

          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    28037115 : static int flags_by_mnt(int mnt_flags)
      15             : {
      16    28037115 :         int flags = 0;
      17             : 
      18    28037115 :         if (mnt_flags & MNT_READONLY)
      19      468856 :                 flags |= ST_RDONLY;
      20    28037115 :         if (mnt_flags & MNT_NOSUID)
      21     1464880 :                 flags |= ST_NOSUID;
      22    28037115 :         if (mnt_flags & MNT_NODEV)
      23      487764 :                 flags |= ST_NODEV;
      24    28037115 :         if (mnt_flags & MNT_NOEXEC)
      25      378840 :                 flags |= ST_NOEXEC;
      26    28037115 :         if (mnt_flags & MNT_NOATIME)
      27       33285 :                 flags |= ST_NOATIME;
      28    28037115 :         if (mnt_flags & MNT_NODIRATIME)
      29           3 :                 flags |= ST_NODIRATIME;
      30    28037115 :         if (mnt_flags & MNT_RELATIME)
      31    27257883 :                 flags |= ST_RELATIME;
      32    28037115 :         if (mnt_flags & MNT_NOSYMFOLLOW)
      33           0 :                 flags |= ST_NOSYMFOLLOW;
      34    28037115 :         return flags;
      35             : }
      36             : 
      37    28027972 : static int flags_by_sb(int s_flags)
      38             : {
      39    28027972 :         int flags = 0;
      40    28027972 :         if (s_flags & SB_SYNCHRONOUS)
      41        3642 :                 flags |= ST_SYNCHRONOUS;
      42    28027972 :         if (s_flags & SB_MANDLOCK)
      43           0 :                 flags |= ST_MANDLOCK;
      44    28027972 :         if (s_flags & SB_RDONLY)
      45       55961 :                 flags |= ST_RDONLY;
      46    28027972 :         return flags;
      47             : }
      48             : 
      49    28037589 : static int calculate_f_flags(struct vfsmount *mnt)
      50             : {
      51    28037589 :         return ST_VALID | flags_by_mnt(mnt->mnt_flags) |
      52    28037589 :                 flags_by_sb(mnt->mnt_sb->s_flags);
      53             : }
      54             : 
      55    28010742 : static int statfs_by_dentry(struct dentry *dentry, struct kstatfs *buf)
      56             : {
      57    28010742 :         int retval;
      58             : 
      59    28010742 :         if (!dentry->d_sb->s_op->statfs)
      60             :                 return -ENOSYS;
      61             : 
      62    28010742 :         memset(buf, 0, sizeof(*buf));
      63    28010742 :         retval = security_sb_statfs(dentry);
      64    28010742 :         if (retval)
      65             :                 return retval;
      66    28010742 :         retval = dentry->d_sb->s_op->statfs(dentry, buf);
      67    28038553 :         if (retval == 0 && buf->f_frsize == 0)
      68    26936263 :                 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    28022395 : int vfs_statfs(const struct path *path, struct kstatfs *buf)
      87             : {
      88    28022395 :         int error;
      89             : 
      90    28022395 :         error = statfs_by_dentry(path->dentry, buf);
      91    28038168 :         if (!error)
      92    28021855 :                 buf->f_flags = calculate_f_flags(path->mnt);
      93    28038168 :         return error;
      94             : }
      95             : EXPORT_SYMBOL(vfs_statfs);
      96             : 
      97    43015873 : int user_statfs(const char __user *pathname, struct kstatfs *st)
      98             : {
      99    43015873 :         struct path path;
     100    43015873 :         int error;
     101    43015873 :         unsigned int lookup_flags = LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT;
     102    43016033 : retry:
     103    43016033 :         error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
     104    43004296 :         if (!error) {
     105    14213475 :                 error = vfs_statfs(&path, st);
     106    14208165 :                 path_put(&path);
     107    28428582 :                 if (retry_estale(error, lookup_flags)) {
     108         177 :                         lookup_flags |= LOOKUP_REVAL;
     109         177 :                         goto retry;
     110             :                 }
     111             :         }
     112    43004952 :         return error;
     113             : }
     114             : 
     115    13026498 : int fd_statfs(int fd, struct kstatfs *st)
     116             : {
     117    13026498 :         struct fd f = fdget_raw(fd);
     118    13032070 :         int error = -EBADF;
     119    13032070 :         if (f.file) {
     120    13032070 :                 error = vfs_statfs(&f.file->f_path, st);
     121    13039940 :                 fdput(f);
     122             :         }
     123    13039942 :         return error;
     124             : }
     125             : 
     126    27246032 : static int do_statfs_native(struct kstatfs *st, struct statfs __user *p)
     127             : {
     128    27246032 :         struct statfs buf;
     129             : 
     130    27246032 :         if (sizeof(buf) == sizeof(*st))
     131    27246032 :                 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    27246032 :         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    86037146 : SYSCALL_DEFINE2(statfs, const char __user *, pathname, struct statfs __user *, buf)
     193             : {
     194    43017348 :         struct kstatfs st;
     195    43017348 :         int error = user_statfs(pathname, &st);
     196    43013609 :         if (!error)
     197    14214699 :                 error = do_statfs_native(&st, buf);
     198    43008643 :         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    26060156 : SYSCALL_DEFINE2(fstatfs, unsigned int, fd, struct statfs __user *, buf)
     214             : {
     215    13029447 :         struct kstatfs st;
     216    13029447 :         int error = fd_statfs(fd, &st);
     217    13040173 :         if (!error)
     218    13039687 :                 error = do_statfs_native(&st, buf);
     219    13037280 :         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           0 : static int put_compat_statfs(struct compat_statfs __user *ubuf, struct kstatfs *kbuf)
     268             : {
     269           0 :         struct compat_statfs buf;
     270           0 :         if (sizeof ubuf->f_blocks == 4) {
     271           0 :                 if ((kbuf->f_blocks | kbuf->f_bfree | kbuf->f_bavail |
     272           0 :                      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           0 :                 if (kbuf->f_files != 0xffffffffffffffffULL
     277           0 :                  && (kbuf->f_files & 0xffffffff00000000ULL))
     278             :                         return -EOVERFLOW;
     279           0 :                 if (kbuf->f_ffree != 0xffffffffffffffffULL
     280           0 :                  && (kbuf->f_ffree & 0xffffffff00000000ULL))
     281             :                         return -EOVERFLOW;
     282             :         }
     283           0 :         memset(&buf, 0, sizeof(struct compat_statfs));
     284           0 :         buf.f_type = kbuf->f_type;
     285           0 :         buf.f_bsize = kbuf->f_bsize;
     286           0 :         buf.f_blocks = kbuf->f_blocks;
     287           0 :         buf.f_bfree = kbuf->f_bfree;
     288           0 :         buf.f_bavail = kbuf->f_bavail;
     289           0 :         buf.f_files = kbuf->f_files;
     290           0 :         buf.f_ffree = kbuf->f_ffree;
     291           0 :         buf.f_namelen = kbuf->f_namelen;
     292           0 :         buf.f_fsid.val[0] = kbuf->f_fsid.val[0];
     293           0 :         buf.f_fsid.val[1] = kbuf->f_fsid.val[1];
     294           0 :         buf.f_frsize = kbuf->f_frsize;
     295           0 :         buf.f_flags = kbuf->f_flags;
     296           0 :         if (copy_to_user(ubuf, &buf, sizeof(struct compat_statfs)))
     297           0 :                 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           0 : COMPAT_SYSCALL_DEFINE2(statfs, const char __user *, pathname, struct compat_statfs __user *, buf)
     306             : {
     307           0 :         struct kstatfs tmp;
     308           0 :         int error = user_statfs(pathname, &tmp);
     309           0 :         if (!error)
     310           0 :                 error = put_compat_statfs(buf, &tmp);
     311           0 :         return error;
     312             : }
     313             : 
     314           0 : COMPAT_SYSCALL_DEFINE2(fstatfs, unsigned int, fd, struct compat_statfs __user *, buf)
     315             : {
     316           0 :         struct kstatfs tmp;
     317           0 :         int error = fd_statfs(fd, &tmp);
     318           0 :         if (!error)
     319           0 :                 error = put_compat_statfs(buf, &tmp);
     320           0 :         return error;
     321             : }
     322             : 
     323           0 : static int put_compat_statfs64(struct compat_statfs64 __user *ubuf, struct kstatfs *kbuf)
     324             : {
     325           0 :         struct compat_statfs64 buf;
     326             : 
     327           0 :         if ((kbuf->f_bsize | kbuf->f_frsize) & 0xffffffff00000000ULL)
     328             :                 return -EOVERFLOW;
     329             : 
     330           0 :         memset(&buf, 0, sizeof(struct compat_statfs64));
     331           0 :         buf.f_type = kbuf->f_type;
     332           0 :         buf.f_bsize = kbuf->f_bsize;
     333           0 :         buf.f_blocks = kbuf->f_blocks;
     334           0 :         buf.f_bfree = kbuf->f_bfree;
     335           0 :         buf.f_bavail = kbuf->f_bavail;
     336           0 :         buf.f_files = kbuf->f_files;
     337           0 :         buf.f_ffree = kbuf->f_ffree;
     338           0 :         buf.f_namelen = kbuf->f_namelen;
     339           0 :         buf.f_fsid.val[0] = kbuf->f_fsid.val[0];
     340           0 :         buf.f_fsid.val[1] = kbuf->f_fsid.val[1];
     341           0 :         buf.f_frsize = kbuf->f_frsize;
     342           0 :         buf.f_flags = kbuf->f_flags;
     343           0 :         if (copy_to_user(ubuf, &buf, sizeof(struct compat_statfs64)))
     344           0 :                 return -EFAULT;
     345             :         return 0;
     346             : }
     347             : 
     348           0 : int kcompat_sys_statfs64(const char __user * pathname, compat_size_t sz, struct compat_statfs64 __user * buf)
     349             : {
     350           0 :         struct kstatfs tmp;
     351           0 :         int error;
     352             : 
     353           0 :         if (sz != sizeof(*buf))
     354             :                 return -EINVAL;
     355             : 
     356           0 :         error = user_statfs(pathname, &tmp);
     357           0 :         if (!error)
     358           0 :                 error = put_compat_statfs64(buf, &tmp);
     359             :         return error;
     360             : }
     361             : 
     362           0 : COMPAT_SYSCALL_DEFINE3(statfs64, const char __user *, pathname, compat_size_t, sz, struct compat_statfs64 __user *, buf)
     363             : {
     364           0 :         return kcompat_sys_statfs64(pathname, sz, buf);
     365             : }
     366             : 
     367           0 : int kcompat_sys_fstatfs64(unsigned int fd, compat_size_t sz, struct compat_statfs64 __user * buf)
     368             : {
     369           0 :         struct kstatfs tmp;
     370           0 :         int error;
     371             : 
     372           0 :         if (sz != sizeof(*buf))
     373             :                 return -EINVAL;
     374             : 
     375           0 :         error = fd_statfs(fd, &tmp);
     376           0 :         if (!error)
     377           0 :                 error = put_compat_statfs64(buf, &tmp);
     378             :         return error;
     379             : }
     380             : 
     381           0 : COMPAT_SYSCALL_DEFINE3(fstatfs64, unsigned int, fd, compat_size_t, sz, struct compat_statfs64 __user *, buf)
     382             : {
     383           0 :         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           0 : COMPAT_SYSCALL_DEFINE2(ustat, unsigned, dev, struct compat_ustat __user *, u)
     392             : {
     393           0 :         struct compat_ustat tmp;
     394           0 :         struct kstatfs sbuf;
     395           0 :         int err = vfs_ustat(new_decode_dev(dev), &sbuf);
     396           0 :         if (err)
     397           0 :                 return err;
     398             : 
     399           0 :         memset(&tmp, 0, sizeof(struct compat_ustat));
     400           0 :         tmp.f_tfree = sbuf.f_bfree;
     401           0 :         tmp.f_tinode = sbuf.f_ffree;
     402           0 :         if (copy_to_user(u, &tmp, sizeof(struct compat_ustat)))
     403           0 :                 return -EFAULT;
     404             :         return 0;
     405             : }
     406             : #endif

Generated by: LCOV version 1.14