linux/fs/statfs.c
<<
>>
Prefs
   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
  14static 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        if (mnt_flags & MNT_NOSYMFOLLOW)
  33                flags |= ST_NOSYMFOLLOW;
  34        return flags;
  35}
  36
  37static int flags_by_sb(int s_flags)
  38{
  39        int flags = 0;
  40        if (s_flags & SB_SYNCHRONOUS)
  41                flags |= ST_SYNCHRONOUS;
  42        if (s_flags & SB_MANDLOCK)
  43                flags |= ST_MANDLOCK;
  44        if (s_flags & SB_RDONLY)
  45                flags |= ST_RDONLY;
  46        return flags;
  47}
  48
  49static int calculate_f_flags(struct vfsmount *mnt)
  50{
  51        return ST_VALID | flags_by_mnt(mnt->mnt_flags) |
  52                flags_by_sb(mnt->mnt_sb->s_flags);
  53}
  54
  55static int statfs_by_dentry(struct dentry *dentry, struct kstatfs *buf)
  56{
  57        int retval;
  58
  59        if (!dentry->d_sb->s_op->statfs)
  60                return -ENOSYS;
  61
  62        memset(buf, 0, sizeof(*buf));
  63        retval = security_sb_statfs(dentry);
  64        if (retval)
  65                return retval;
  66        retval = dentry->d_sb->s_op->statfs(dentry, buf);
  67        if (retval == 0 && buf->f_frsize == 0)
  68                buf->f_frsize = buf->f_bsize;
  69        return retval;
  70}
  71
  72int vfs_get_fsid(struct dentry *dentry, __kernel_fsid_t *fsid)
  73{
  74        struct kstatfs st;
  75        int error;
  76
  77        error = statfs_by_dentry(dentry, &st);
  78        if (error)
  79                return error;
  80
  81        *fsid = st.f_fsid;
  82        return 0;
  83}
  84EXPORT_SYMBOL(vfs_get_fsid);
  85
  86int vfs_statfs(const struct path *path, struct kstatfs *buf)
  87{
  88        int error;
  89
  90        error = statfs_by_dentry(path->dentry, buf);
  91        if (!error)
  92                buf->f_flags = calculate_f_flags(path->mnt);
  93        return error;
  94}
  95EXPORT_SYMBOL(vfs_statfs);
  96
  97int user_statfs(const char __user *pathname, struct kstatfs *st)
  98{
  99        struct path path;
 100        int error;
 101        unsigned int lookup_flags = LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT;
 102retry:
 103        error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
 104        if (!error) {
 105                error = vfs_statfs(&path, st);
 106                path_put(&path);
 107                if (retry_estale(error, lookup_flags)) {
 108                        lookup_flags |= LOOKUP_REVAL;
 109                        goto retry;
 110                }
 111        }
 112        return error;
 113}
 114
 115int fd_statfs(int fd, struct kstatfs *st)
 116{
 117        struct fd f = fdget_raw(fd);
 118        int error = -EBADF;
 119        if (f.file) {
 120                error = vfs_statfs(&f.file->f_path, st);
 121                fdput(f);
 122        }
 123        return error;
 124}
 125
 126static int do_statfs_native(struct kstatfs *st, struct statfs __user *p)
 127{
 128        struct statfs buf;
 129
 130        if (sizeof(buf) == sizeof(*st))
 131                memcpy(&buf, st, sizeof(*st));
 132        else {
 133                if (sizeof buf.f_blocks == 4) {
 134                        if ((st->f_blocks | st->f_bfree | st->f_bavail |
 135                             st->f_bsize | st->f_frsize) &
 136                            0xffffffff00000000ULL)
 137                                return -EOVERFLOW;
 138                        /*
 139                         * f_files and f_ffree may be -1; it's okay to stuff
 140                         * that into 32 bits
 141                         */
 142                        if (st->f_files != -1 &&
 143                            (st->f_files & 0xffffffff00000000ULL))
 144                                return -EOVERFLOW;
 145                        if (st->f_ffree != -1 &&
 146                            (st->f_ffree & 0xffffffff00000000ULL))
 147                                return -EOVERFLOW;
 148                }
 149
 150                buf.f_type = st->f_type;
 151                buf.f_bsize = st->f_bsize;
 152                buf.f_blocks = st->f_blocks;
 153                buf.f_bfree = st->f_bfree;
 154                buf.f_bavail = st->f_bavail;
 155                buf.f_files = st->f_files;
 156                buf.f_ffree = st->f_ffree;
 157                buf.f_fsid = st->f_fsid;
 158                buf.f_namelen = st->f_namelen;
 159                buf.f_frsize = st->f_frsize;
 160                buf.f_flags = st->f_flags;
 161                memset(buf.f_spare, 0, sizeof(buf.f_spare));
 162        }
 163        if (copy_to_user(p, &buf, sizeof(buf)))
 164                return -EFAULT;
 165        return 0;
 166}
 167
 168static int do_statfs64(struct kstatfs *st, struct statfs64 __user *p)
 169{
 170        struct statfs64 buf;
 171        if (sizeof(buf) == sizeof(*st))
 172                memcpy(&buf, st, sizeof(*st));
 173        else {
 174                buf.f_type = st->f_type;
 175                buf.f_bsize = st->f_bsize;
 176                buf.f_blocks = st->f_blocks;
 177                buf.f_bfree = st->f_bfree;
 178                buf.f_bavail = st->f_bavail;
 179                buf.f_files = st->f_files;
 180                buf.f_ffree = st->f_ffree;
 181                buf.f_fsid = st->f_fsid;
 182                buf.f_namelen = st->f_namelen;
 183                buf.f_frsize = st->f_frsize;
 184                buf.f_flags = st->f_flags;
 185                memset(buf.f_spare, 0, sizeof(buf.f_spare));
 186        }
 187        if (copy_to_user(p, &buf, sizeof(buf)))
 188                return -EFAULT;
 189        return 0;
 190}
 191
 192SYSCALL_DEFINE2(statfs, const char __user *, pathname, struct statfs __user *, buf)
 193{
 194        struct kstatfs st;
 195        int error = user_statfs(pathname, &st);
 196        if (!error)
 197                error = do_statfs_native(&st, buf);
 198        return error;
 199}
 200
 201SYSCALL_DEFINE3(statfs64, const char __user *, pathname, size_t, sz, struct statfs64 __user *, buf)
 202{
 203        struct kstatfs st;
 204        int error;
 205        if (sz != sizeof(*buf))
 206                return -EINVAL;
 207        error = user_statfs(pathname, &st);
 208        if (!error)
 209                error = do_statfs64(&st, buf);
 210        return error;
 211}
 212
 213SYSCALL_DEFINE2(fstatfs, unsigned int, fd, struct statfs __user *, buf)
 214{
 215        struct kstatfs st;
 216        int error = fd_statfs(fd, &st);
 217        if (!error)
 218                error = do_statfs_native(&st, buf);
 219        return error;
 220}
 221
 222SYSCALL_DEFINE3(fstatfs64, unsigned int, fd, size_t, sz, struct statfs64 __user *, buf)
 223{
 224        struct kstatfs st;
 225        int error;
 226
 227        if (sz != sizeof(*buf))
 228                return -EINVAL;
 229
 230        error = fd_statfs(fd, &st);
 231        if (!error)
 232                error = do_statfs64(&st, buf);
 233        return error;
 234}
 235
 236static int vfs_ustat(dev_t dev, struct kstatfs *sbuf)
 237{
 238        struct super_block *s = user_get_super(dev, false);
 239        int err;
 240        if (!s)
 241                return -EINVAL;
 242
 243        err = statfs_by_dentry(s->s_root, sbuf);
 244        drop_super(s);
 245        return err;
 246}
 247
 248SYSCALL_DEFINE2(ustat, unsigned, dev, struct ustat __user *, ubuf)
 249{
 250        struct ustat tmp;
 251        struct kstatfs sbuf;
 252        int err = vfs_ustat(new_decode_dev(dev), &sbuf);
 253        if (err)
 254                return err;
 255
 256        memset(&tmp,0,sizeof(struct ustat));
 257        tmp.f_tfree = sbuf.f_bfree;
 258        if (IS_ENABLED(CONFIG_ARCH_32BIT_USTAT_F_TINODE))
 259                tmp.f_tinode = min_t(u64, sbuf.f_ffree, UINT_MAX);
 260        else
 261                tmp.f_tinode = sbuf.f_ffree;
 262
 263        return copy_to_user(ubuf, &tmp, sizeof(struct ustat)) ? -EFAULT : 0;
 264}
 265
 266#ifdef CONFIG_COMPAT
 267static 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 */
 305COMPAT_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
 314COMPAT_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
 323static 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
 348int 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
 362COMPAT_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
 367int 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
 381COMPAT_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 */
 391COMPAT_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
 407