LCOV - code coverage report
Current view: top level - fs - d_path.c (source / functions) Hit Total Coverage
Test: Real Lines: 116 155 74.8 %
Date: 2020-10-17 15:46:43 Functions: 0 15 0.0 %
Legend: Neither, QEMU, Real, Both Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: GPL-2.0 */
       2                 :            : #include <linux/syscalls.h>
       3                 :            : #include <linux/export.h>
       4                 :            : #include <linux/uaccess.h>
       5                 :            : #include <linux/fs_struct.h>
       6                 :            : #include <linux/fs.h>
       7                 :            : #include <linux/slab.h>
       8                 :            : #include <linux/prefetch.h>
       9                 :            : #include "mount.h"
      10                 :            : 
      11                 :          3 : static int prepend(char **buffer, int *buflen, const char *str, int namelen)
      12                 :            : {
      13                 :          3 :         *buflen -= namelen;
      14                 :          3 :         if (*buflen < 0)
      15                 :            :                 return -ENAMETOOLONG;
      16                 :          3 :         *buffer -= namelen;
      17                 :          3 :         memcpy(*buffer, str, namelen);
      18                 :          3 :         return 0;
      19                 :            : }
      20                 :            : 
      21                 :            : /**
      22                 :            :  * prepend_name - prepend a pathname in front of current buffer pointer
      23                 :            :  * @buffer: buffer pointer
      24                 :            :  * @buflen: allocated length of the buffer
      25                 :            :  * @name:   name string and length qstr structure
      26                 :            :  *
      27                 :            :  * With RCU path tracing, it may race with d_move(). Use READ_ONCE() to
      28                 :            :  * make sure that either the old or the new name pointer and length are
      29                 :            :  * fetched. However, there may be mismatch between length and pointer.
      30                 :            :  * The length cannot be trusted, we need to copy it byte-by-byte until
      31                 :            :  * the length is reached or a null byte is found. It also prepends "/" at
      32                 :            :  * the beginning of the name. The sequence number check at the caller will
      33                 :            :  * retry it again when a d_move() does happen. So any garbage in the buffer
      34                 :            :  * due to mismatched pointer and length will be discarded.
      35                 :            :  *
      36                 :            :  * Load acquire is needed to make sure that we see that terminating NUL.
      37                 :            :  */
      38                 :          3 : static int prepend_name(char **buffer, int *buflen, const struct qstr *name)
      39                 :            : {
      40                 :          3 :         const char *dname = smp_load_acquire(&name->name); /* ^^^ */
      41                 :            :         u32 dlen = READ_ONCE(name->len);
      42                 :            :         char *p;
      43                 :            : 
      44                 :          3 :         *buflen -= dlen + 1;
      45                 :          3 :         if (*buflen < 0)
      46                 :            :                 return -ENAMETOOLONG;
      47                 :          3 :         p = *buffer -= dlen + 1;
      48                 :          3 :         *p++ = '/';
      49                 :          3 :         while (dlen--) {
      50                 :          3 :                 char c = *dname++;
      51                 :          3 :                 if (!c)
      52                 :            :                         break;
      53                 :          3 :                 *p++ = c;
      54                 :            :         }
      55                 :            :         return 0;
      56                 :            : }
      57                 :            : 
      58                 :            : /**
      59                 :            :  * prepend_path - Prepend path string to a buffer
      60                 :            :  * @path: the dentry/vfsmount to report
      61                 :            :  * @root: root vfsmnt/dentry
      62                 :            :  * @buffer: pointer to the end of the buffer
      63                 :            :  * @buflen: pointer to buffer length
      64                 :            :  *
      65                 :            :  * The function will first try to write out the pathname without taking any
      66                 :            :  * lock other than the RCU read lock to make sure that dentries won't go away.
      67                 :            :  * It only checks the sequence number of the global rename_lock as any change
      68                 :            :  * in the dentry's d_seq will be preceded by changes in the rename_lock
      69                 :            :  * sequence number. If the sequence number had been changed, it will restart
      70                 :            :  * the whole pathname back-tracing sequence again by taking the rename_lock.
      71                 :            :  * In this case, there is no need to take the RCU read lock as the recursive
      72                 :            :  * parent pointer references will keep the dentry chain alive as long as no
      73                 :            :  * rename operation is performed.
      74                 :            :  */
      75                 :          3 : static int prepend_path(const struct path *path,
      76                 :            :                         const struct path *root,
      77                 :            :                         char **buffer, int *buflen)
      78                 :            : {
      79                 :            :         struct dentry *dentry;
      80                 :            :         struct vfsmount *vfsmnt;
      81                 :            :         struct mount *mnt;
      82                 :            :         int error = 0;
      83                 :          3 :         unsigned seq, m_seq = 0;
      84                 :            :         char *bptr;
      85                 :            :         int blen;
      86                 :            : 
      87                 :            :         rcu_read_lock();
      88                 :            : restart_mnt:
      89                 :          3 :         read_seqbegin_or_lock(&mount_lock, &m_seq);
      90                 :          3 :         seq = 0;
      91                 :            :         rcu_read_lock();
      92                 :            : restart:
      93                 :          3 :         bptr = *buffer;
      94                 :          3 :         blen = *buflen;
      95                 :            :         error = 0;
      96                 :          3 :         dentry = path->dentry;
      97                 :          3 :         vfsmnt = path->mnt;
      98                 :            :         mnt = real_mount(vfsmnt);
      99                 :          3 :         read_seqbegin_or_lock(&rename_lock, &seq);
     100                 :          3 :         while (dentry != root->dentry || vfsmnt != root->mnt) {
     101                 :            :                 struct dentry * parent;
     102                 :            : 
     103                 :          3 :                 if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
     104                 :          3 :                         struct mount *parent = READ_ONCE(mnt->mnt_parent);
     105                 :            :                         /* Escaped? */
     106                 :          3 :                         if (dentry != vfsmnt->mnt_root) {
     107                 :          0 :                                 bptr = *buffer;
     108                 :          0 :                                 blen = *buflen;
     109                 :            :                                 error = 3;
     110                 :          0 :                                 break;
     111                 :            :                         }
     112                 :            :                         /* Global root? */
     113                 :          3 :                         if (mnt != parent) {
     114                 :          3 :                                 dentry = READ_ONCE(mnt->mnt_mountpoint);
     115                 :            :                                 mnt = parent;
     116                 :          3 :                                 vfsmnt = &mnt->mnt;
     117                 :          3 :                                 continue;
     118                 :            :                         }
     119                 :          3 :                         if (is_mounted(vfsmnt) && !is_anon_ns(mnt->mnt_ns))
     120                 :            :                                 error = 1;      // absolute root
     121                 :            :                         else
     122                 :            :                                 error = 2;      // detached or not attached yet
     123                 :            :                         break;
     124                 :            :                 }
     125                 :            :                 parent = dentry->d_parent;
     126                 :            :                 prefetch(parent);
     127                 :          3 :                 error = prepend_name(&bptr, &blen, &dentry->d_name);
     128                 :          3 :                 if (error)
     129                 :            :                         break;
     130                 :            : 
     131                 :            :                 dentry = parent;
     132                 :            :         }
     133                 :          3 :         if (!(seq & 1))
     134                 :            :                 rcu_read_unlock();
     135                 :          3 :         if (need_seqretry(&rename_lock, seq)) {
     136                 :          3 :                 seq = 1;
     137                 :          3 :                 goto restart;
     138                 :            :         }
     139                 :          3 :         done_seqretry(&rename_lock, seq);
     140                 :            : 
     141                 :          3 :         if (!(m_seq & 1))
     142                 :            :                 rcu_read_unlock();
     143                 :          3 :         if (need_seqretry(&mount_lock, m_seq)) {
     144                 :          3 :                 m_seq = 1;
     145                 :          3 :                 goto restart_mnt;
     146                 :            :         }
     147                 :          3 :         done_seqretry(&mount_lock, m_seq);
     148                 :            : 
     149                 :          3 :         if (error >= 0 && bptr == *buffer) {
     150                 :          3 :                 if (--blen < 0)
     151                 :            :                         error = -ENAMETOOLONG;
     152                 :            :                 else
     153                 :          3 :                         *--bptr = '/';
     154                 :            :         }
     155                 :          3 :         *buffer = bptr;
     156                 :          3 :         *buflen = blen;
     157                 :          3 :         return error;
     158                 :            : }
     159                 :            : 
     160                 :            : /**
     161                 :            :  * __d_path - return the path of a dentry
     162                 :            :  * @path: the dentry/vfsmount to report
     163                 :            :  * @root: root vfsmnt/dentry
     164                 :            :  * @buf: buffer to return value in
     165                 :            :  * @buflen: buffer length
     166                 :            :  *
     167                 :            :  * Convert a dentry into an ASCII path name.
     168                 :            :  *
     169                 :            :  * Returns a pointer into the buffer or an error code if the
     170                 :            :  * path was too long.
     171                 :            :  *
     172                 :            :  * "buflen" should be positive.
     173                 :            :  *
     174                 :            :  * If the path is not reachable from the supplied root, return %NULL.
     175                 :            :  */
     176                 :          3 : char *__d_path(const struct path *path,
     177                 :            :                const struct path *root,
     178                 :            :                char *buf, int buflen)
     179                 :            : {
     180                 :          3 :         char *res = buf + buflen;
     181                 :            :         int error;
     182                 :            : 
     183                 :          3 :         prepend(&res, &buflen, "\0", 1);
     184                 :          3 :         error = prepend_path(path, root, &res, &buflen);
     185                 :            : 
     186                 :          3 :         if (error < 0)
     187                 :          0 :                 return ERR_PTR(error);
     188                 :          3 :         if (error > 0)
     189                 :            :                 return NULL;
     190                 :          3 :         return res;
     191                 :            : }
     192                 :            : 
     193                 :          0 : char *d_absolute_path(const struct path *path,
     194                 :            :                char *buf, int buflen)
     195                 :            : {
     196                 :          0 :         struct path root = {};
     197                 :          0 :         char *res = buf + buflen;
     198                 :            :         int error;
     199                 :            : 
     200                 :          0 :         prepend(&res, &buflen, "\0", 1);
     201                 :          0 :         error = prepend_path(path, &root, &res, &buflen);
     202                 :            : 
     203                 :          0 :         if (error > 1)
     204                 :            :                 error = -EINVAL;
     205                 :          0 :         if (error < 0)
     206                 :          0 :                 return ERR_PTR(error);
     207                 :          0 :         return res;
     208                 :            : }
     209                 :            : 
     210                 :            : /*
     211                 :            :  * same as __d_path but appends "(deleted)" for unlinked files.
     212                 :            :  */
     213                 :          3 : static int path_with_deleted(const struct path *path,
     214                 :            :                              const struct path *root,
     215                 :            :                              char **buf, int *buflen)
     216                 :            : {
     217                 :          3 :         prepend(buf, buflen, "\0", 1);
     218                 :          3 :         if (d_unlinked(path->dentry)) {
     219                 :            :                 int error = prepend(buf, buflen, " (deleted)", 10);
     220                 :          0 :                 if (error)
     221                 :            :                         return error;
     222                 :            :         }
     223                 :            : 
     224                 :          3 :         return prepend_path(path, root, buf, buflen);
     225                 :            : }
     226                 :            : 
     227                 :          0 : static int prepend_unreachable(char **buffer, int *buflen)
     228                 :            : {
     229                 :          0 :         return prepend(buffer, buflen, "(unreachable)", 13);
     230                 :            : }
     231                 :            : 
     232                 :            : static void get_fs_root_rcu(struct fs_struct *fs, struct path *root)
     233                 :            : {
     234                 :            :         unsigned seq;
     235                 :            : 
     236                 :            :         do {
     237                 :            :                 seq = read_seqcount_begin(&fs->seq);
     238                 :          3 :                 *root = fs->root;
     239                 :          3 :         } while (read_seqcount_retry(&fs->seq, seq));
     240                 :            : }
     241                 :            : 
     242                 :            : /**
     243                 :            :  * d_path - return the path of a dentry
     244                 :            :  * @path: path to report
     245                 :            :  * @buf: buffer to return value in
     246                 :            :  * @buflen: buffer length
     247                 :            :  *
     248                 :            :  * Convert a dentry into an ASCII path name. If the entry has been deleted
     249                 :            :  * the string " (deleted)" is appended. Note that this is ambiguous.
     250                 :            :  *
     251                 :            :  * Returns a pointer into the buffer or an error code if the path was
     252                 :            :  * too long. Note: Callers should use the returned pointer, not the passed
     253                 :            :  * in buffer, to use the name! The implementation often starts at an offset
     254                 :            :  * into the buffer, and may leave 0 bytes at the start.
     255                 :            :  *
     256                 :            :  * "buflen" should be positive.
     257                 :            :  */
     258                 :          3 : char *d_path(const struct path *path, char *buf, int buflen)
     259                 :            : {
     260                 :          3 :         char *res = buf + buflen;
     261                 :            :         struct path root;
     262                 :            :         int error;
     263                 :            : 
     264                 :            :         /*
     265                 :            :          * We have various synthetic filesystems that never get mounted.  On
     266                 :            :          * these filesystems dentries are never used for lookup purposes, and
     267                 :            :          * thus don't need to be hashed.  They also don't need a name until a
     268                 :            :          * user wants to identify the object in /proc/pid/fd/.  The little hack
     269                 :            :          * below allows us to generate a name for these objects on demand:
     270                 :            :          *
     271                 :            :          * Some pseudo inodes are mountable.  When they are mounted
     272                 :            :          * path->dentry == path->mnt->mnt_root.  In that case don't call d_dname
     273                 :            :          * and instead have d_path return the mounted path.
     274                 :            :          */
     275                 :          3 :         if (path->dentry->d_op && path->dentry->d_op->d_dname &&
     276                 :          0 :             (!IS_ROOT(path->dentry) || path->dentry != path->mnt->mnt_root))
     277                 :          0 :                 return path->dentry->d_op->d_dname(path->dentry, buf, buflen);
     278                 :            : 
     279                 :            :         rcu_read_lock();
     280                 :          3 :         get_fs_root_rcu(current->fs, &root);
     281                 :          3 :         error = path_with_deleted(path, &root, &res, &buflen);
     282                 :            :         rcu_read_unlock();
     283                 :            : 
     284                 :          3 :         if (error < 0)
     285                 :          0 :                 res = ERR_PTR(error);
     286                 :          3 :         return res;
     287                 :            : }
     288                 :            : EXPORT_SYMBOL(d_path);
     289                 :            : 
     290                 :            : /*
     291                 :            :  * Helper function for dentry_operations.d_dname() members
     292                 :            :  */
     293                 :          0 : char *dynamic_dname(struct dentry *dentry, char *buffer, int buflen,
     294                 :            :                         const char *fmt, ...)
     295                 :            : {
     296                 :            :         va_list args;
     297                 :            :         char temp[64];
     298                 :            :         int sz;
     299                 :            : 
     300                 :          0 :         va_start(args, fmt);
     301                 :          0 :         sz = vsnprintf(temp, sizeof(temp), fmt, args) + 1;
     302                 :          0 :         va_end(args);
     303                 :            : 
     304                 :          0 :         if (sz > sizeof(temp) || sz > buflen)
     305                 :            :                 return ERR_PTR(-ENAMETOOLONG);
     306                 :            : 
     307                 :          0 :         buffer += buflen - sz;
     308                 :          0 :         return memcpy(buffer, temp, sz);
     309                 :            : }
     310                 :            : 
     311                 :          0 : char *simple_dname(struct dentry *dentry, char *buffer, int buflen)
     312                 :            : {
     313                 :          0 :         char *end = buffer + buflen;
     314                 :            :         /* these dentries are never renamed, so d_lock is not needed */
     315                 :          0 :         if (prepend(&end, &buflen, " (deleted)", 11) ||
     316                 :          0 :             prepend(&end, &buflen, dentry->d_name.name, dentry->d_name.len) ||
     317                 :            :             prepend(&end, &buflen, "/", 1))  
     318                 :            :                 end = ERR_PTR(-ENAMETOOLONG);
     319                 :          0 :         return end;
     320                 :            : }
     321                 :            : 
     322                 :            : /*
     323                 :            :  * Write full pathname from the root of the filesystem into the buffer.
     324                 :            :  */
     325                 :          3 : static char *__dentry_path(struct dentry *d, char *buf, int buflen)
     326                 :            : {
     327                 :            :         struct dentry *dentry;
     328                 :            :         char *end, *retval;
     329                 :          3 :         int len, seq = 0;
     330                 :            :         int error = 0;
     331                 :            : 
     332                 :          3 :         if (buflen < 2)
     333                 :            :                 goto Elong;
     334                 :            : 
     335                 :            :         rcu_read_lock();
     336                 :            : restart:
     337                 :            :         dentry = d;
     338                 :          3 :         end = buf + buflen;
     339                 :          3 :         len = buflen;
     340                 :          3 :         prepend(&end, &len, "\0", 1);
     341                 :            :         /* Get '/' right */
     342                 :          3 :         retval = end-1;
     343                 :          3 :         *retval = '/';
     344                 :          3 :         read_seqbegin_or_lock(&rename_lock, &seq);
     345                 :          3 :         while (!IS_ROOT(dentry)) {
     346                 :            :                 struct dentry *parent = dentry->d_parent;
     347                 :            : 
     348                 :            :                 prefetch(parent);
     349                 :          3 :                 error = prepend_name(&end, &len, &dentry->d_name);
     350                 :          3 :                 if (error)
     351                 :            :                         break;
     352                 :            : 
     353                 :          3 :                 retval = end;
     354                 :            :                 dentry = parent;
     355                 :            :         }
     356                 :          3 :         if (!(seq & 1))
     357                 :            :                 rcu_read_unlock();
     358                 :          3 :         if (need_seqretry(&rename_lock, seq)) {
     359                 :          1 :                 seq = 1;
     360                 :          1 :                 goto restart;
     361                 :            :         }
     362                 :          3 :         done_seqretry(&rename_lock, seq);
     363                 :          3 :         if (error)
     364                 :            :                 goto Elong;
     365                 :          3 :         return retval;
     366                 :            : Elong:
     367                 :            :         return ERR_PTR(-ENAMETOOLONG);
     368                 :            : }
     369                 :            : 
     370                 :          0 : char *dentry_path_raw(struct dentry *dentry, char *buf, int buflen)
     371                 :            : {
     372                 :          0 :         return __dentry_path(dentry, buf, buflen);
     373                 :            : }
     374                 :            : EXPORT_SYMBOL(dentry_path_raw);
     375                 :            : 
     376                 :          3 : char *dentry_path(struct dentry *dentry, char *buf, int buflen)
     377                 :            : {
     378                 :            :         char *p = NULL;
     379                 :            :         char *retval;
     380                 :            : 
     381                 :          3 :         if (d_unlinked(dentry)) {
     382                 :          0 :                 p = buf + buflen;
     383                 :          0 :                 if (prepend(&p, &buflen, "//deleted", 10) != 0)
     384                 :            :                         goto Elong;
     385                 :          0 :                 buflen++;
     386                 :            :         }
     387                 :          3 :         retval = __dentry_path(dentry, buf, buflen);
     388                 :          3 :         if (!IS_ERR(retval) && p)
     389                 :          0 :                 *p = '/';       /* restore '/' overriden with '\0' */
     390                 :          3 :         return retval;
     391                 :            : Elong:
     392                 :            :         return ERR_PTR(-ENAMETOOLONG);
     393                 :            : }
     394                 :            : 
     395                 :            : static void get_fs_root_and_pwd_rcu(struct fs_struct *fs, struct path *root,
     396                 :            :                                     struct path *pwd)
     397                 :            : {
     398                 :            :         unsigned seq;
     399                 :            : 
     400                 :            :         do {
     401                 :            :                 seq = read_seqcount_begin(&fs->seq);
     402                 :          3 :                 *root = fs->root;
     403                 :          3 :                 *pwd = fs->pwd;
     404                 :          3 :         } while (read_seqcount_retry(&fs->seq, seq));
     405                 :            : }
     406                 :            : 
     407                 :            : /*
     408                 :            :  * NOTE! The user-level library version returns a
     409                 :            :  * character pointer. The kernel system call just
     410                 :            :  * returns the length of the buffer filled (which
     411                 :            :  * includes the ending '\0' character), or a negative
     412                 :            :  * error value. So libc would do something like
     413                 :            :  *
     414                 :            :  *      char *getcwd(char * buf, size_t size)
     415                 :            :  *      {
     416                 :            :  *              int retval;
     417                 :            :  *
     418                 :            :  *              retval = sys_getcwd(buf, size);
     419                 :            :  *              if (retval >= 0)
     420                 :            :  *                      return buf;
     421                 :            :  *              errno = -retval;
     422                 :            :  *              return NULL;
     423                 :            :  *      }
     424                 :            :  */
     425                 :          3 : SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size)
     426                 :            : {
     427                 :            :         int error;
     428                 :            :         struct path pwd, root;
     429                 :          3 :         char *page = __getname();
     430                 :            : 
     431                 :          3 :         if (!page)
     432                 :            :                 return -ENOMEM;
     433                 :            : 
     434                 :            :         rcu_read_lock();
     435                 :          3 :         get_fs_root_and_pwd_rcu(current->fs, &root, &pwd);
     436                 :            : 
     437                 :            :         error = -ENOENT;
     438                 :          3 :         if (!d_unlinked(pwd.dentry)) {
     439                 :            :                 unsigned long len;
     440                 :          3 :                 char *cwd = page + PATH_MAX;
     441                 :          3 :                 int buflen = PATH_MAX;
     442                 :            : 
     443                 :          3 :                 prepend(&cwd, &buflen, "\0", 1);
     444                 :          3 :                 error = prepend_path(&pwd, &root, &cwd, &buflen);
     445                 :            :                 rcu_read_unlock();
     446                 :            : 
     447                 :          3 :                 if (error < 0)
     448                 :            :                         goto out;
     449                 :            : 
     450                 :            :                 /* Unreachable from current root */
     451                 :          3 :                 if (error > 0) {
     452                 :          0 :                         error = prepend_unreachable(&cwd, &buflen);
     453                 :          0 :                         if (error)
     454                 :            :                                 goto out;
     455                 :            :                 }
     456                 :            : 
     457                 :            :                 error = -ERANGE;
     458                 :          3 :                 len = PATH_MAX + page - cwd;
     459                 :          3 :                 if (len <= size) {
     460                 :            :                         error = len;
     461                 :          3 :                         if (copy_to_user(buf, cwd, len))
     462                 :            :                                 error = -EFAULT;
     463                 :            :                 }
     464                 :            :         } else {
     465                 :            :                 rcu_read_unlock();
     466                 :            :         }
     467                 :            : 
     468                 :            : out:
     469                 :          3 :         __putname(page);
     470                 :          3 :         return error;
     471                 :            : }
    

Generated by: LCOV version 1.14