LCOV - code coverage report
Current view: top level - fs/exportfs - expfs.c (source / functions) Hit Total Coverage
Test: landlock.info Lines: 0 242 0.0 %
Date: 2021-04-22 12:43:58 Functions: 0 13 0.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0-only
       2             : /*
       3             :  * Copyright (C) Neil Brown 2002
       4             :  * Copyright (C) Christoph Hellwig 2007
       5             :  *
       6             :  * This file contains the code mapping from inodes to NFS file handles,
       7             :  * and for mapping back from file handles to dentries.
       8             :  *
       9             :  * For details on why we do all the strange and hairy things in here
      10             :  * take a look at Documentation/filesystems/nfs/exporting.rst.
      11             :  */
      12             : #include <linux/exportfs.h>
      13             : #include <linux/fs.h>
      14             : #include <linux/file.h>
      15             : #include <linux/module.h>
      16             : #include <linux/mount.h>
      17             : #include <linux/namei.h>
      18             : #include <linux/sched.h>
      19             : #include <linux/cred.h>
      20             : 
      21             : #define dprintk(fmt, args...) do{}while(0)
      22             : 
      23             : 
      24             : static int get_name(const struct path *path, char *name, struct dentry *child);
      25             : 
      26             : 
      27           0 : static int exportfs_get_name(struct vfsmount *mnt, struct dentry *dir,
      28             :                 char *name, struct dentry *child)
      29             : {
      30           0 :         const struct export_operations *nop = dir->d_sb->s_export_op;
      31           0 :         struct path path = {.mnt = mnt, .dentry = dir};
      32             : 
      33           0 :         if (nop->get_name)
      34           0 :                 return nop->get_name(dir, name, child);
      35             :         else
      36           0 :                 return get_name(&path, name, child);
      37             : }
      38             : 
      39             : /*
      40             :  * Check if the dentry or any of it's aliases is acceptable.
      41             :  */
      42             : static struct dentry *
      43           0 : find_acceptable_alias(struct dentry *result,
      44             :                 int (*acceptable)(void *context, struct dentry *dentry),
      45             :                 void *context)
      46             : {
      47           0 :         struct dentry *dentry, *toput = NULL;
      48           0 :         struct inode *inode;
      49             : 
      50           0 :         if (acceptable(context, result))
      51             :                 return result;
      52             : 
      53           0 :         inode = result->d_inode;
      54           0 :         spin_lock(&inode->i_lock);
      55           0 :         hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) {
      56           0 :                 dget(dentry);
      57           0 :                 spin_unlock(&inode->i_lock);
      58           0 :                 if (toput)
      59           0 :                         dput(toput);
      60           0 :                 if (dentry != result && acceptable(context, dentry)) {
      61           0 :                         dput(result);
      62           0 :                         return dentry;
      63             :                 }
      64           0 :                 spin_lock(&inode->i_lock);
      65           0 :                 toput = dentry;
      66             :         }
      67           0 :         spin_unlock(&inode->i_lock);
      68             : 
      69           0 :         if (toput)
      70           0 :                 dput(toput);
      71             :         return NULL;
      72             : }
      73             : 
      74           0 : static bool dentry_connected(struct dentry *dentry)
      75             : {
      76           0 :         dget(dentry);
      77           0 :         while (dentry->d_flags & DCACHE_DISCONNECTED) {
      78           0 :                 struct dentry *parent = dget_parent(dentry);
      79             : 
      80           0 :                 dput(dentry);
      81           0 :                 if (dentry == parent) {
      82           0 :                         dput(parent);
      83           0 :                         return false;
      84             :                 }
      85             :                 dentry = parent;
      86             :         }
      87           0 :         dput(dentry);
      88           0 :         return true;
      89             : }
      90             : 
      91           0 : static void clear_disconnected(struct dentry *dentry)
      92             : {
      93           0 :         dget(dentry);
      94           0 :         while (dentry->d_flags & DCACHE_DISCONNECTED) {
      95           0 :                 struct dentry *parent = dget_parent(dentry);
      96             : 
      97           0 :                 WARN_ON_ONCE(IS_ROOT(dentry));
      98             : 
      99           0 :                 spin_lock(&dentry->d_lock);
     100           0 :                 dentry->d_flags &= ~DCACHE_DISCONNECTED;
     101           0 :                 spin_unlock(&dentry->d_lock);
     102             : 
     103           0 :                 dput(dentry);
     104           0 :                 dentry = parent;
     105             :         }
     106           0 :         dput(dentry);
     107           0 : }
     108             : 
     109             : /*
     110             :  * Reconnect a directory dentry with its parent.
     111             :  *
     112             :  * This can return a dentry, or NULL, or an error.
     113             :  *
     114             :  * In the first case the returned dentry is the parent of the given
     115             :  * dentry, and may itself need to be reconnected to its parent.
     116             :  *
     117             :  * In the NULL case, a concurrent VFS operation has either renamed or
     118             :  * removed this directory.  The concurrent operation has reconnected our
     119             :  * dentry, so we no longer need to.
     120             :  */
     121           0 : static struct dentry *reconnect_one(struct vfsmount *mnt,
     122             :                 struct dentry *dentry, char *nbuf)
     123             : {
     124           0 :         struct dentry *parent;
     125           0 :         struct dentry *tmp;
     126           0 :         int err;
     127             : 
     128           0 :         parent = ERR_PTR(-EACCES);
     129           0 :         inode_lock(dentry->d_inode);
     130           0 :         if (mnt->mnt_sb->s_export_op->get_parent)
     131           0 :                 parent = mnt->mnt_sb->s_export_op->get_parent(dentry);
     132           0 :         inode_unlock(dentry->d_inode);
     133             : 
     134           0 :         if (IS_ERR(parent)) {
     135             :                 dprintk("%s: get_parent of %ld failed, err %d\n",
     136             :                         __func__, dentry->d_inode->i_ino, PTR_ERR(parent));
     137             :                 return parent;
     138             :         }
     139             : 
     140           0 :         dprintk("%s: find name of %lu in %lu\n", __func__,
     141             :                 dentry->d_inode->i_ino, parent->d_inode->i_ino);
     142           0 :         err = exportfs_get_name(mnt, parent, nbuf, dentry);
     143           0 :         if (err == -ENOENT)
     144           0 :                 goto out_reconnected;
     145           0 :         if (err)
     146           0 :                 goto out_err;
     147           0 :         dprintk("%s: found name: %s\n", __func__, nbuf);
     148           0 :         tmp = lookup_one_len_unlocked(nbuf, parent, strlen(nbuf));
     149           0 :         if (IS_ERR(tmp)) {
     150           0 :                 dprintk("%s: lookup failed: %d\n", __func__, PTR_ERR(tmp));
     151           0 :                 err = PTR_ERR(tmp);
     152           0 :                 goto out_err;
     153             :         }
     154           0 :         if (tmp != dentry) {
     155             :                 /*
     156             :                  * Somebody has renamed it since exportfs_get_name();
     157             :                  * great, since it could've only been renamed if it
     158             :                  * got looked up and thus connected, and it would
     159             :                  * remain connected afterwards.  We are done.
     160             :                  */
     161           0 :                 dput(tmp);
     162           0 :                 goto out_reconnected;
     163             :         }
     164           0 :         dput(tmp);
     165           0 :         if (IS_ROOT(dentry)) {
     166           0 :                 err = -ESTALE;
     167           0 :                 goto out_err;
     168             :         }
     169             :         return parent;
     170             : 
     171           0 : out_err:
     172           0 :         dput(parent);
     173           0 :         return ERR_PTR(err);
     174           0 : out_reconnected:
     175           0 :         dput(parent);
     176             :         /*
     177             :          * Someone must have renamed our entry into another parent, in
     178             :          * which case it has been reconnected by the rename.
     179             :          *
     180             :          * Or someone removed it entirely, in which case filehandle
     181             :          * lookup will succeed but the directory is now IS_DEAD and
     182             :          * subsequent operations on it will fail.
     183             :          *
     184             :          * Alternatively, maybe there was no race at all, and the
     185             :          * filesystem is just corrupt and gave us a parent that doesn't
     186             :          * actually contain any entry pointing to this inode.  So,
     187             :          * double check that this worked and return -ESTALE if not:
     188             :          */
     189           0 :         if (!dentry_connected(dentry))
     190           0 :                 return ERR_PTR(-ESTALE);
     191             :         return NULL;
     192             : }
     193             : 
     194             : /*
     195             :  * Make sure target_dir is fully connected to the dentry tree.
     196             :  *
     197             :  * On successful return, DCACHE_DISCONNECTED will be cleared on
     198             :  * target_dir, and target_dir->d_parent->...->d_parent will reach the
     199             :  * root of the filesystem.
     200             :  *
     201             :  * Whenever DCACHE_DISCONNECTED is unset, target_dir is fully connected.
     202             :  * But the converse is not true: target_dir may have DCACHE_DISCONNECTED
     203             :  * set but already be connected.  In that case we'll verify the
     204             :  * connection to root and then clear the flag.
     205             :  *
     206             :  * Note that target_dir could be removed by a concurrent operation.  In
     207             :  * that case reconnect_path may still succeed with target_dir fully
     208             :  * connected, but further operations using the filehandle will fail when
     209             :  * necessary (due to S_DEAD being set on the directory).
     210             :  */
     211             : static int
     212           0 : reconnect_path(struct vfsmount *mnt, struct dentry *target_dir, char *nbuf)
     213             : {
     214           0 :         struct dentry *dentry, *parent;
     215             : 
     216           0 :         dentry = dget(target_dir);
     217             : 
     218           0 :         while (dentry->d_flags & DCACHE_DISCONNECTED) {
     219           0 :                 BUG_ON(dentry == mnt->mnt_sb->s_root);
     220             : 
     221           0 :                 if (IS_ROOT(dentry))
     222           0 :                         parent = reconnect_one(mnt, dentry, nbuf);
     223             :                 else
     224           0 :                         parent = dget_parent(dentry);
     225             : 
     226           0 :                 if (!parent)
     227             :                         break;
     228           0 :                 dput(dentry);
     229           0 :                 if (IS_ERR(parent))
     230           0 :                         return PTR_ERR(parent);
     231             :                 dentry = parent;
     232             :         }
     233           0 :         dput(dentry);
     234           0 :         clear_disconnected(target_dir);
     235           0 :         return 0;
     236             : }
     237             : 
     238             : struct getdents_callback {
     239             :         struct dir_context ctx;
     240             :         char *name;             /* name that was found. It already points to a
     241             :                                    buffer NAME_MAX+1 is size */
     242             :         u64 ino;                /* the inum we are looking for */
     243             :         int found;              /* inode matched? */
     244             :         int sequence;           /* sequence counter */
     245             : };
     246             : 
     247             : /*
     248             :  * A rather strange filldir function to capture
     249             :  * the name matching the specified inode number.
     250             :  */
     251           0 : static int filldir_one(struct dir_context *ctx, const char *name, int len,
     252             :                         loff_t pos, u64 ino, unsigned int d_type)
     253             : {
     254           0 :         struct getdents_callback *buf =
     255           0 :                 container_of(ctx, struct getdents_callback, ctx);
     256           0 :         int result = 0;
     257             : 
     258           0 :         buf->sequence++;
     259           0 :         if (buf->ino == ino && len <= NAME_MAX) {
     260           0 :                 memcpy(buf->name, name, len);
     261           0 :                 buf->name[len] = '\0';
     262           0 :                 buf->found = 1;
     263           0 :                 result = -1;
     264             :         }
     265           0 :         return result;
     266             : }
     267             : 
     268             : /**
     269             :  * get_name - default export_operations->get_name function
     270             :  * @path:   the directory in which to find a name
     271             :  * @name:   a pointer to a %NAME_MAX+1 char buffer to store the name
     272             :  * @child:  the dentry for the child directory.
     273             :  *
     274             :  * calls readdir on the parent until it finds an entry with
     275             :  * the same inode number as the child, and returns that.
     276             :  */
     277           0 : static int get_name(const struct path *path, char *name, struct dentry *child)
     278             : {
     279           0 :         const struct cred *cred = current_cred();
     280           0 :         struct inode *dir = path->dentry->d_inode;
     281           0 :         int error;
     282           0 :         struct file *file;
     283           0 :         struct kstat stat;
     284           0 :         struct path child_path = {
     285           0 :                 .mnt = path->mnt,
     286             :                 .dentry = child,
     287             :         };
     288           0 :         struct getdents_callback buffer = {
     289             :                 .ctx.actor = filldir_one,
     290             :                 .name = name,
     291             :         };
     292             : 
     293           0 :         error = -ENOTDIR;
     294           0 :         if (!dir || !S_ISDIR(dir->i_mode))
     295           0 :                 goto out;
     296           0 :         error = -EINVAL;
     297           0 :         if (!dir->i_fop)
     298           0 :                 goto out;
     299             :         /*
     300             :          * inode->i_ino is unsigned long, kstat->ino is u64, so the
     301             :          * former would be insufficient on 32-bit hosts when the
     302             :          * filesystem supports 64-bit inode numbers.  So we need to
     303             :          * actually call ->getattr, not just read i_ino:
     304             :          */
     305           0 :         error = vfs_getattr_nosec(&child_path, &stat,
     306             :                                   STATX_INO, AT_STATX_SYNC_AS_STAT);
     307           0 :         if (error)
     308             :                 return error;
     309           0 :         buffer.ino = stat.ino;
     310             :         /*
     311             :          * Open the directory ...
     312             :          */
     313           0 :         file = dentry_open(path, O_RDONLY, cred);
     314           0 :         error = PTR_ERR(file);
     315           0 :         if (IS_ERR(file))
     316           0 :                 goto out;
     317             : 
     318           0 :         error = -EINVAL;
     319           0 :         if (!file->f_op->iterate && !file->f_op->iterate_shared)
     320           0 :                 goto out_close;
     321             : 
     322           0 :         buffer.sequence = 0;
     323           0 :         while (1) {
     324           0 :                 int old_seq = buffer.sequence;
     325             : 
     326           0 :                 error = iterate_dir(file, &buffer.ctx);
     327           0 :                 if (buffer.found) {
     328             :                         error = 0;
     329             :                         break;
     330             :                 }
     331             : 
     332           0 :                 if (error < 0)
     333             :                         break;
     334             : 
     335           0 :                 error = -ENOENT;
     336           0 :                 if (old_seq == buffer.sequence)
     337             :                         break;
     338             :         }
     339             : 
     340           0 : out_close:
     341           0 :         fput(file);
     342             : out:
     343             :         return error;
     344             : }
     345             : 
     346             : /**
     347             :  * export_encode_fh - default export_operations->encode_fh function
     348             :  * @inode:   the object to encode
     349             :  * @fid:     where to store the file handle fragment
     350             :  * @max_len: maximum length to store there
     351             :  * @parent:  parent directory inode, if wanted
     352             :  *
     353             :  * This default encode_fh function assumes that the 32 inode number
     354             :  * is suitable for locating an inode, and that the generation number
     355             :  * can be used to check that it is still valid.  It places them in the
     356             :  * filehandle fragment where export_decode_fh expects to find them.
     357             :  */
     358           0 : static int export_encode_fh(struct inode *inode, struct fid *fid,
     359             :                 int *max_len, struct inode *parent)
     360             : {
     361           0 :         int len = *max_len;
     362           0 :         int type = FILEID_INO32_GEN;
     363             : 
     364           0 :         if (parent && (len < 4)) {
     365           0 :                 *max_len = 4;
     366           0 :                 return FILEID_INVALID;
     367           0 :         } else if (len < 2) {
     368           0 :                 *max_len = 2;
     369           0 :                 return FILEID_INVALID;
     370             :         }
     371             : 
     372           0 :         len = 2;
     373           0 :         fid->i32.ino = inode->i_ino;
     374           0 :         fid->i32.gen = inode->i_generation;
     375           0 :         if (parent) {
     376           0 :                 fid->i32.parent_ino = parent->i_ino;
     377           0 :                 fid->i32.parent_gen = parent->i_generation;
     378           0 :                 len = 4;
     379           0 :                 type = FILEID_INO32_GEN_PARENT;
     380             :         }
     381           0 :         *max_len = len;
     382           0 :         return type;
     383             : }
     384             : 
     385           0 : int exportfs_encode_inode_fh(struct inode *inode, struct fid *fid,
     386             :                              int *max_len, struct inode *parent)
     387             : {
     388           0 :         const struct export_operations *nop = inode->i_sb->s_export_op;
     389             : 
     390           0 :         if (nop && nop->encode_fh)
     391           0 :                 return nop->encode_fh(inode, fid->raw, max_len, parent);
     392             : 
     393           0 :         return export_encode_fh(inode, fid, max_len, parent);
     394             : }
     395             : EXPORT_SYMBOL_GPL(exportfs_encode_inode_fh);
     396             : 
     397           0 : int exportfs_encode_fh(struct dentry *dentry, struct fid *fid, int *max_len,
     398             :                 int connectable)
     399             : {
     400           0 :         int error;
     401           0 :         struct dentry *p = NULL;
     402           0 :         struct inode *inode = dentry->d_inode, *parent = NULL;
     403             : 
     404           0 :         if (connectable && !S_ISDIR(inode->i_mode)) {
     405           0 :                 p = dget_parent(dentry);
     406             :                 /*
     407             :                  * note that while p might've ceased to be our parent already,
     408             :                  * it's still pinned by and still positive.
     409             :                  */
     410           0 :                 parent = p->d_inode;
     411             :         }
     412             : 
     413           0 :         error = exportfs_encode_inode_fh(inode, fid, max_len, parent);
     414           0 :         dput(p);
     415             : 
     416           0 :         return error;
     417             : }
     418             : EXPORT_SYMBOL_GPL(exportfs_encode_fh);
     419             : 
     420             : struct dentry *
     421           0 : exportfs_decode_fh_raw(struct vfsmount *mnt, struct fid *fid, int fh_len,
     422             :                        int fileid_type,
     423             :                        int (*acceptable)(void *, struct dentry *),
     424             :                        void *context)
     425             : {
     426           0 :         const struct export_operations *nop = mnt->mnt_sb->s_export_op;
     427           0 :         struct dentry *result, *alias;
     428           0 :         char nbuf[NAME_MAX+1];
     429           0 :         int err;
     430             : 
     431             :         /*
     432             :          * Try to get any dentry for the given file handle from the filesystem.
     433             :          */
     434           0 :         if (!nop || !nop->fh_to_dentry)
     435           0 :                 return ERR_PTR(-ESTALE);
     436           0 :         result = nop->fh_to_dentry(mnt->mnt_sb, fid, fh_len, fileid_type);
     437           0 :         if (IS_ERR_OR_NULL(result))
     438             :                 return result;
     439             : 
     440             :         /*
     441             :          * If no acceptance criteria was specified by caller, a disconnected
     442             :          * dentry is also accepatable. Callers may use this mode to query if
     443             :          * file handle is stale or to get a reference to an inode without
     444             :          * risking the high overhead caused by directory reconnect.
     445             :          */
     446           0 :         if (!acceptable)
     447             :                 return result;
     448             : 
     449           0 :         if (d_is_dir(result)) {
     450             :                 /*
     451             :                  * This request is for a directory.
     452             :                  *
     453             :                  * On the positive side there is only one dentry for each
     454             :                  * directory inode.  On the negative side this implies that we
     455             :                  * to ensure our dentry is connected all the way up to the
     456             :                  * filesystem root.
     457             :                  */
     458           0 :                 if (result->d_flags & DCACHE_DISCONNECTED) {
     459           0 :                         err = reconnect_path(mnt, result, nbuf);
     460           0 :                         if (err)
     461           0 :                                 goto err_result;
     462             :                 }
     463             : 
     464           0 :                 if (!acceptable(context, result)) {
     465           0 :                         err = -EACCES;
     466           0 :                         goto err_result;
     467             :                 }
     468             : 
     469             :                 return result;
     470             :         } else {
     471             :                 /*
     472             :                  * It's not a directory.  Life is a little more complicated.
     473             :                  */
     474           0 :                 struct dentry *target_dir, *nresult;
     475             : 
     476             :                 /*
     477             :                  * See if either the dentry we just got from the filesystem
     478             :                  * or any alias for it is acceptable.  This is always true
     479             :                  * if this filesystem is exported without the subtreecheck
     480             :                  * option.  If the filesystem is exported with the subtree
     481             :                  * check option there's a fair chance we need to look at
     482             :                  * the parent directory in the file handle and make sure
     483             :                  * it's connected to the filesystem root.
     484             :                  */
     485           0 :                 alias = find_acceptable_alias(result, acceptable, context);
     486           0 :                 if (alias)
     487             :                         return alias;
     488             : 
     489             :                 /*
     490             :                  * Try to extract a dentry for the parent directory from the
     491             :                  * file handle.  If this fails we'll have to give up.
     492             :                  */
     493           0 :                 err = -ESTALE;
     494           0 :                 if (!nop->fh_to_parent)
     495           0 :                         goto err_result;
     496             : 
     497           0 :                 target_dir = nop->fh_to_parent(mnt->mnt_sb, fid,
     498             :                                 fh_len, fileid_type);
     499           0 :                 if (!target_dir)
     500           0 :                         goto err_result;
     501           0 :                 err = PTR_ERR(target_dir);
     502           0 :                 if (IS_ERR(target_dir))
     503           0 :                         goto err_result;
     504             : 
     505             :                 /*
     506             :                  * And as usual we need to make sure the parent directory is
     507             :                  * connected to the filesystem root.  The VFS really doesn't
     508             :                  * like disconnected directories..
     509             :                  */
     510           0 :                 err = reconnect_path(mnt, target_dir, nbuf);
     511           0 :                 if (err) {
     512           0 :                         dput(target_dir);
     513           0 :                         goto err_result;
     514             :                 }
     515             : 
     516             :                 /*
     517             :                  * Now that we've got both a well-connected parent and a
     518             :                  * dentry for the inode we're after, make sure that our
     519             :                  * inode is actually connected to the parent.
     520             :                  */
     521           0 :                 err = exportfs_get_name(mnt, target_dir, nbuf, result);
     522           0 :                 if (err) {
     523           0 :                         dput(target_dir);
     524           0 :                         goto err_result;
     525             :                 }
     526             : 
     527           0 :                 inode_lock(target_dir->d_inode);
     528           0 :                 nresult = lookup_one_len(nbuf, target_dir, strlen(nbuf));
     529           0 :                 if (!IS_ERR(nresult)) {
     530           0 :                         if (unlikely(nresult->d_inode != result->d_inode)) {
     531           0 :                                 dput(nresult);
     532           0 :                                 nresult = ERR_PTR(-ESTALE);
     533             :                         }
     534             :                 }
     535           0 :                 inode_unlock(target_dir->d_inode);
     536             :                 /*
     537             :                  * At this point we are done with the parent, but it's pinned
     538             :                  * by the child dentry anyway.
     539             :                  */
     540           0 :                 dput(target_dir);
     541             : 
     542           0 :                 if (IS_ERR(nresult)) {
     543           0 :                         err = PTR_ERR(nresult);
     544           0 :                         goto err_result;
     545             :                 }
     546           0 :                 dput(result);
     547           0 :                 result = nresult;
     548             : 
     549             :                 /*
     550             :                  * And finally make sure the dentry is actually acceptable
     551             :                  * to NFSD.
     552             :                  */
     553           0 :                 alias = find_acceptable_alias(result, acceptable, context);
     554           0 :                 if (!alias) {
     555           0 :                         err = -EACCES;
     556           0 :                         goto err_result;
     557             :                 }
     558             : 
     559             :                 return alias;
     560             :         }
     561             : 
     562           0 :  err_result:
     563           0 :         dput(result);
     564           0 :         return ERR_PTR(err);
     565             : }
     566             : EXPORT_SYMBOL_GPL(exportfs_decode_fh_raw);
     567             : 
     568           0 : struct dentry *exportfs_decode_fh(struct vfsmount *mnt, struct fid *fid,
     569             :                                   int fh_len, int fileid_type,
     570             :                                   int (*acceptable)(void *, struct dentry *),
     571             :                                   void *context)
     572             : {
     573           0 :         struct dentry *ret;
     574             : 
     575           0 :         ret = exportfs_decode_fh_raw(mnt, fid, fh_len, fileid_type,
     576             :                                      acceptable, context);
     577           0 :         if (IS_ERR_OR_NULL(ret)) {
     578           0 :                 if (ret == ERR_PTR(-ENOMEM))
     579             :                         return ret;
     580           0 :                 return ERR_PTR(-ESTALE);
     581             :         }
     582             :         return ret;
     583             : }
     584             : EXPORT_SYMBOL_GPL(exportfs_decode_fh);
     585             : 
     586             : MODULE_LICENSE("GPL");

Generated by: LCOV version 1.14