LCOV - code coverage report
Current view: top level - fs - readdir.c (source / functions) Hit Total Coverage
Test: landlock.info Lines: 67 242 27.7 %
Date: 2021-04-22 12:43:58 Functions: 5 20 25.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0
       2             : /*
       3             :  *  linux/fs/readdir.c
       4             :  *
       5             :  *  Copyright (C) 1995  Linus Torvalds
       6             :  */
       7             : 
       8             : #include <linux/stddef.h>
       9             : #include <linux/kernel.h>
      10             : #include <linux/export.h>
      11             : #include <linux/time.h>
      12             : #include <linux/mm.h>
      13             : #include <linux/errno.h>
      14             : #include <linux/stat.h>
      15             : #include <linux/file.h>
      16             : #include <linux/fs.h>
      17             : #include <linux/fsnotify.h>
      18             : #include <linux/dirent.h>
      19             : #include <linux/security.h>
      20             : #include <linux/syscalls.h>
      21             : #include <linux/unistd.h>
      22             : #include <linux/compat.h>
      23             : #include <linux/uaccess.h>
      24             : 
      25             : #include <asm/unaligned.h>
      26             : 
      27             : /*
      28             :  * Note the "unsafe_put_user() semantics: we goto a
      29             :  * label for errors.
      30             :  */
      31             : #define unsafe_copy_dirent_name(_dst, _src, _len, label) do {   \
      32             :         char __user *dst = (_dst);                              \
      33             :         const char *src = (_src);                               \
      34             :         size_t len = (_len);                                    \
      35             :         unsafe_put_user(0, dst+len, label);                     \
      36             :         unsafe_copy_to_user(dst, src, len, label);              \
      37             : } while (0)
      38             : 
      39             : 
      40        1999 : int iterate_dir(struct file *file, struct dir_context *ctx)
      41             : {
      42        1999 :         struct inode *inode = file_inode(file);
      43        1999 :         bool shared = false;
      44        1999 :         int res = -ENOTDIR;
      45        1999 :         if (file->f_op->iterate_shared)
      46             :                 shared = true;
      47           0 :         else if (!file->f_op->iterate)
      48           0 :                 goto out;
      49             : 
      50        1999 :         res = security_file_permission(file, MAY_READ);
      51        1999 :         if (res)
      52           0 :                 goto out;
      53             : 
      54        1999 :         if (shared)
      55        1999 :                 res = down_read_killable(&inode->i_rwsem);
      56             :         else
      57           0 :                 res = down_write_killable(&inode->i_rwsem);
      58        1999 :         if (res)
      59           0 :                 goto out;
      60             : 
      61        1999 :         res = -ENOENT;
      62        1999 :         if (!IS_DEADDIR(inode)) {
      63        1999 :                 ctx->pos = file->f_pos;
      64        1999 :                 if (shared)
      65        1999 :                         res = file->f_op->iterate_shared(file, ctx);
      66             :                 else
      67           0 :                         res = file->f_op->iterate(file, ctx);
      68        1999 :                 file->f_pos = ctx->pos;
      69        1999 :                 fsnotify_access(file);
      70        1999 :                 file_accessed(file);
      71             :         }
      72        1999 :         if (shared)
      73        1999 :                 inode_unlock_shared(inode);
      74             :         else
      75           0 :                 inode_unlock(inode);
      76        1999 : out:
      77        1999 :         return res;
      78             : }
      79             : EXPORT_SYMBOL(iterate_dir);
      80             : 
      81             : /*
      82             :  * POSIX says that a dirent name cannot contain NULL or a '/'.
      83             :  *
      84             :  * It's not 100% clear what we should really do in this case.
      85             :  * The filesystem is clearly corrupted, but returning a hard
      86             :  * error means that you now don't see any of the other names
      87             :  * either, so that isn't a perfect alternative.
      88             :  *
      89             :  * And if you return an error, what error do you use? Several
      90             :  * filesystems seem to have decided on EUCLEAN being the error
      91             :  * code for EFSCORRUPTED, and that may be the error to use. Or
      92             :  * just EIO, which is perhaps more obvious to users.
      93             :  *
      94             :  * In order to see the other file names in the directory, the
      95             :  * caller might want to make this a "soft" error: skip the
      96             :  * entry, and return the error at the end instead.
      97             :  *
      98             :  * Note that this should likely do a "memchr(name, 0, len)"
      99             :  * check too, since that would be filesystem corruption as
     100             :  * well. However, that case can't actually confuse user space,
     101             :  * which has to do a strlen() on the name anyway to find the
     102             :  * filename length, and the above "soft error" worry means
     103             :  * that it's probably better left alone until we have that
     104             :  * issue clarified.
     105             :  *
     106             :  * Note the PATH_MAX check - it's arbitrary but the real
     107             :  * kernel limit on a possible path component, not NAME_MAX,
     108             :  * which is the technical standard limit.
     109             :  */
     110       14495 : static int verify_dirent_name(const char *name, int len)
     111             : {
     112       14495 :         if (len <= 0 || len >= PATH_MAX)
     113             :                 return -EIO;
     114       14495 :         if (memchr(name, '/', len))
     115           0 :                 return -EIO;
     116             :         return 0;
     117             : }
     118             : 
     119             : /*
     120             :  * Traditional linux readdir() handling..
     121             :  *
     122             :  * "count=1" is a special case, meaning that the buffer is one
     123             :  * dirent-structure in size and that the code can't handle more
     124             :  * anyway. Thus the special "fillonedir()" function for that
     125             :  * case (the low-level handlers don't need to care about this).
     126             :  */
     127             : 
     128             : #ifdef __ARCH_WANT_OLD_READDIR
     129             : 
     130             : struct old_linux_dirent {
     131             :         unsigned long   d_ino;
     132             :         unsigned long   d_offset;
     133             :         unsigned short  d_namlen;
     134             :         char            d_name[1];
     135             : };
     136             : 
     137             : struct readdir_callback {
     138             :         struct dir_context ctx;
     139             :         struct old_linux_dirent __user * dirent;
     140             :         int result;
     141             : };
     142             : 
     143           0 : static int fillonedir(struct dir_context *ctx, const char *name, int namlen,
     144             :                       loff_t offset, u64 ino, unsigned int d_type)
     145             : {
     146           0 :         struct readdir_callback *buf =
     147           0 :                 container_of(ctx, struct readdir_callback, ctx);
     148           0 :         struct old_linux_dirent __user * dirent;
     149           0 :         unsigned long d_ino;
     150             : 
     151           0 :         if (buf->result)
     152             :                 return -EINVAL;
     153           0 :         d_ino = ino;
     154           0 :         if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
     155             :                 buf->result = -EOVERFLOW;
     156             :                 return -EOVERFLOW;
     157             :         }
     158           0 :         buf->result++;
     159           0 :         dirent = buf->dirent;
     160           0 :         if (!user_write_access_begin(dirent,
     161             :                         (unsigned long)(dirent->d_name + namlen + 1) -
     162             :                                 (unsigned long)dirent))
     163           0 :                 goto efault;
     164           0 :         unsafe_put_user(d_ino, &dirent->d_ino, efault_end);
     165           0 :         unsafe_put_user(offset, &dirent->d_offset, efault_end);
     166           0 :         unsafe_put_user(namlen, &dirent->d_namlen, efault_end);
     167           0 :         unsafe_copy_dirent_name(dirent->d_name, name, namlen, efault_end);
     168             :         user_write_access_end();
     169             :         return 0;
     170           0 : efault_end:
     171             :         user_write_access_end();
     172           0 : efault:
     173           0 :         buf->result = -EFAULT;
     174           0 :         return -EFAULT;
     175             : }
     176             : 
     177           0 : SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
     178             :                 struct old_linux_dirent __user *, dirent, unsigned int, count)
     179             : {
     180           0 :         int error;
     181           0 :         struct fd f = fdget_pos(fd);
     182           0 :         struct readdir_callback buf = {
     183             :                 .ctx.actor = fillonedir,
     184             :                 .dirent = dirent
     185             :         };
     186             : 
     187           0 :         if (!f.file)
     188             :                 return -EBADF;
     189             : 
     190           0 :         error = iterate_dir(f.file, &buf.ctx);
     191           0 :         if (buf.result)
     192           0 :                 error = buf.result;
     193             : 
     194           0 :         fdput_pos(f);
     195           0 :         return error;
     196             : }
     197             : 
     198             : #endif /* __ARCH_WANT_OLD_READDIR */
     199             : 
     200             : /*
     201             :  * New, all-improved, singing, dancing, iBCS2-compliant getdents()
     202             :  * interface. 
     203             :  */
     204             : struct linux_dirent {
     205             :         unsigned long   d_ino;
     206             :         unsigned long   d_off;
     207             :         unsigned short  d_reclen;
     208             :         char            d_name[1];
     209             : };
     210             : 
     211             : struct getdents_callback {
     212             :         struct dir_context ctx;
     213             :         struct linux_dirent __user * current_dir;
     214             :         int prev_reclen;
     215             :         int count;
     216             :         int error;
     217             : };
     218             : 
     219           0 : static int filldir(struct dir_context *ctx, const char *name, int namlen,
     220             :                    loff_t offset, u64 ino, unsigned int d_type)
     221             : {
     222           0 :         struct linux_dirent __user *dirent, *prev;
     223           0 :         struct getdents_callback *buf =
     224           0 :                 container_of(ctx, struct getdents_callback, ctx);
     225           0 :         unsigned long d_ino;
     226           0 :         int reclen = ALIGN(offsetof(struct linux_dirent, d_name) + namlen + 2,
     227             :                 sizeof(long));
     228           0 :         int prev_reclen;
     229             : 
     230           0 :         buf->error = verify_dirent_name(name, namlen);
     231           0 :         if (unlikely(buf->error))
     232             :                 return buf->error;
     233           0 :         buf->error = -EINVAL;        /* only used if we fail.. */
     234           0 :         if (reclen > buf->count)
     235             :                 return -EINVAL;
     236           0 :         d_ino = ino;
     237           0 :         if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
     238             :                 buf->error = -EOVERFLOW;
     239             :                 return -EOVERFLOW;
     240             :         }
     241           0 :         prev_reclen = buf->prev_reclen;
     242           0 :         if (prev_reclen && signal_pending(current))
     243             :                 return -EINTR;
     244           0 :         dirent = buf->current_dir;
     245           0 :         prev = (void __user *) dirent - prev_reclen;
     246           0 :         if (!user_write_access_begin(prev, reclen + prev_reclen))
     247           0 :                 goto efault;
     248             : 
     249             :         /* This might be 'dirent->d_off', but if so it will get overwritten */
     250           0 :         unsafe_put_user(offset, &prev->d_off, efault_end);
     251           0 :         unsafe_put_user(d_ino, &dirent->d_ino, efault_end);
     252           0 :         unsafe_put_user(reclen, &dirent->d_reclen, efault_end);
     253           0 :         unsafe_put_user(d_type, (char __user *) dirent + reclen - 1, efault_end);
     254           0 :         unsafe_copy_dirent_name(dirent->d_name, name, namlen, efault_end);
     255           0 :         user_write_access_end();
     256             : 
     257           0 :         buf->current_dir = (void __user *)dirent + reclen;
     258           0 :         buf->prev_reclen = reclen;
     259           0 :         buf->count -= reclen;
     260           0 :         return 0;
     261           0 : efault_end:
     262             :         user_write_access_end();
     263           0 : efault:
     264           0 :         buf->error = -EFAULT;
     265           0 :         return -EFAULT;
     266             : }
     267             : 
     268           0 : SYSCALL_DEFINE3(getdents, unsigned int, fd,
     269             :                 struct linux_dirent __user *, dirent, unsigned int, count)
     270             : {
     271           0 :         struct fd f;
     272           0 :         struct getdents_callback buf = {
     273             :                 .ctx.actor = filldir,
     274             :                 .count = count,
     275             :                 .current_dir = dirent
     276             :         };
     277           0 :         int error;
     278             : 
     279           0 :         f = fdget_pos(fd);
     280           0 :         if (!f.file)
     281             :                 return -EBADF;
     282             : 
     283           0 :         error = iterate_dir(f.file, &buf.ctx);
     284           0 :         if (error >= 0)
     285           0 :                 error = buf.error;
     286           0 :         if (buf.prev_reclen) {
     287           0 :                 struct linux_dirent __user * lastdirent;
     288           0 :                 lastdirent = (void __user *)buf.current_dir - buf.prev_reclen;
     289             : 
     290           0 :                 if (put_user(buf.ctx.pos, &lastdirent->d_off))
     291             :                         error = -EFAULT;
     292             :                 else
     293           0 :                         error = count - buf.count;
     294             :         }
     295           0 :         fdput_pos(f);
     296           0 :         return error;
     297             : }
     298             : 
     299             : struct getdents_callback64 {
     300             :         struct dir_context ctx;
     301             :         struct linux_dirent64 __user * current_dir;
     302             :         int prev_reclen;
     303             :         int count;
     304             :         int error;
     305             : };
     306             : 
     307       14495 : static int filldir64(struct dir_context *ctx, const char *name, int namlen,
     308             :                      loff_t offset, u64 ino, unsigned int d_type)
     309             : {
     310       14495 :         struct linux_dirent64 __user *dirent, *prev;
     311       14495 :         struct getdents_callback64 *buf =
     312       14495 :                 container_of(ctx, struct getdents_callback64, ctx);
     313       14495 :         int reclen = ALIGN(offsetof(struct linux_dirent64, d_name) + namlen + 1,
     314             :                 sizeof(u64));
     315       14495 :         int prev_reclen;
     316             : 
     317       14495 :         buf->error = verify_dirent_name(name, namlen);
     318       14495 :         if (unlikely(buf->error))
     319             :                 return buf->error;
     320       14495 :         buf->error = -EINVAL;        /* only used if we fail.. */
     321       14495 :         if (reclen > buf->count)
     322             :                 return -EINVAL;
     323       14494 :         prev_reclen = buf->prev_reclen;
     324       14494 :         if (prev_reclen && signal_pending(current))
     325             :                 return -EINTR;
     326       14494 :         dirent = buf->current_dir;
     327       14494 :         prev = (void __user *)dirent - prev_reclen;
     328       14494 :         if (!user_write_access_begin(prev, reclen + prev_reclen))
     329           0 :                 goto efault;
     330             : 
     331             :         /* This might be 'dirent->d_off', but if so it will get overwritten */
     332       14494 :         unsafe_put_user(offset, &prev->d_off, efault_end);
     333       14494 :         unsafe_put_user(ino, &dirent->d_ino, efault_end);
     334       14494 :         unsafe_put_user(reclen, &dirent->d_reclen, efault_end);
     335       14494 :         unsafe_put_user(d_type, &dirent->d_type, efault_end);
     336       47299 :         unsafe_copy_dirent_name(dirent->d_name, name, namlen, efault_end);
     337       14494 :         user_write_access_end();
     338             : 
     339       14494 :         buf->prev_reclen = reclen;
     340       14494 :         buf->current_dir = (void __user *)dirent + reclen;
     341       14494 :         buf->count -= reclen;
     342       14494 :         return 0;
     343             : 
     344           0 : efault_end:
     345             :         user_write_access_end();
     346           0 : efault:
     347           0 :         buf->error = -EFAULT;
     348           0 :         return -EFAULT;
     349             : }
     350             : 
     351        3994 : SYSCALL_DEFINE3(getdents64, unsigned int, fd,
     352             :                 struct linux_dirent64 __user *, dirent, unsigned int, count)
     353             : {
     354        1997 :         struct fd f;
     355        1997 :         struct getdents_callback64 buf = {
     356             :                 .ctx.actor = filldir64,
     357             :                 .count = count,
     358             :                 .current_dir = dirent
     359             :         };
     360        1997 :         int error;
     361             : 
     362        1997 :         f = fdget_pos(fd);
     363        1997 :         if (!f.file)
     364             :                 return -EBADF;
     365             : 
     366        1997 :         error = iterate_dir(f.file, &buf.ctx);
     367        1997 :         if (error >= 0)
     368        1997 :                 error = buf.error;
     369        1997 :         if (buf.prev_reclen) {
     370        1007 :                 struct linux_dirent64 __user * lastdirent;
     371        1007 :                 typeof(lastdirent->d_off) d_off = buf.ctx.pos;
     372             : 
     373        1007 :                 lastdirent = (void __user *) buf.current_dir - buf.prev_reclen;
     374        1007 :                 if (put_user(d_off, &lastdirent->d_off))
     375             :                         error = -EFAULT;
     376             :                 else
     377        1007 :                         error = count - buf.count;
     378             :         }
     379        1997 :         fdput_pos(f);
     380        1997 :         return error;
     381             : }
     382             : 
     383             : #ifdef CONFIG_COMPAT
     384             : struct compat_old_linux_dirent {
     385             :         compat_ulong_t  d_ino;
     386             :         compat_ulong_t  d_offset;
     387             :         unsigned short  d_namlen;
     388             :         char            d_name[1];
     389             : };
     390             : 
     391             : struct compat_readdir_callback {
     392             :         struct dir_context ctx;
     393             :         struct compat_old_linux_dirent __user *dirent;
     394             :         int result;
     395             : };
     396             : 
     397           0 : static int compat_fillonedir(struct dir_context *ctx, const char *name,
     398             :                              int namlen, loff_t offset, u64 ino,
     399             :                              unsigned int d_type)
     400             : {
     401           0 :         struct compat_readdir_callback *buf =
     402           0 :                 container_of(ctx, struct compat_readdir_callback, ctx);
     403           0 :         struct compat_old_linux_dirent __user *dirent;
     404           0 :         compat_ulong_t d_ino;
     405             : 
     406           0 :         if (buf->result)
     407             :                 return -EINVAL;
     408           0 :         d_ino = ino;
     409           0 :         if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
     410           0 :                 buf->result = -EOVERFLOW;
     411           0 :                 return -EOVERFLOW;
     412             :         }
     413           0 :         buf->result++;
     414           0 :         dirent = buf->dirent;
     415           0 :         if (!user_write_access_begin(dirent,
     416             :                         (unsigned long)(dirent->d_name + namlen + 1) -
     417             :                                 (unsigned long)dirent))
     418           0 :                 goto efault;
     419           0 :         unsafe_put_user(d_ino, &dirent->d_ino, efault_end);
     420           0 :         unsafe_put_user(offset, &dirent->d_offset, efault_end);
     421           0 :         unsafe_put_user(namlen, &dirent->d_namlen, efault_end);
     422           0 :         unsafe_copy_dirent_name(dirent->d_name, name, namlen, efault_end);
     423             :         user_write_access_end();
     424             :         return 0;
     425           0 : efault_end:
     426             :         user_write_access_end();
     427           0 : efault:
     428           0 :         buf->result = -EFAULT;
     429           0 :         return -EFAULT;
     430             : }
     431             : 
     432           0 : COMPAT_SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
     433             :                 struct compat_old_linux_dirent __user *, dirent, unsigned int, count)
     434             : {
     435           0 :         int error;
     436           0 :         struct fd f = fdget_pos(fd);
     437           0 :         struct compat_readdir_callback buf = {
     438             :                 .ctx.actor = compat_fillonedir,
     439             :                 .dirent = dirent
     440             :         };
     441             : 
     442           0 :         if (!f.file)
     443             :                 return -EBADF;
     444             : 
     445           0 :         error = iterate_dir(f.file, &buf.ctx);
     446           0 :         if (buf.result)
     447           0 :                 error = buf.result;
     448             : 
     449           0 :         fdput_pos(f);
     450           0 :         return error;
     451             : }
     452             : 
     453             : struct compat_linux_dirent {
     454             :         compat_ulong_t  d_ino;
     455             :         compat_ulong_t  d_off;
     456             :         unsigned short  d_reclen;
     457             :         char            d_name[1];
     458             : };
     459             : 
     460             : struct compat_getdents_callback {
     461             :         struct dir_context ctx;
     462             :         struct compat_linux_dirent __user *current_dir;
     463             :         int prev_reclen;
     464             :         int count;
     465             :         int error;
     466             : };
     467             : 
     468           0 : static int compat_filldir(struct dir_context *ctx, const char *name, int namlen,
     469             :                 loff_t offset, u64 ino, unsigned int d_type)
     470             : {
     471           0 :         struct compat_linux_dirent __user *dirent, *prev;
     472           0 :         struct compat_getdents_callback *buf =
     473           0 :                 container_of(ctx, struct compat_getdents_callback, ctx);
     474           0 :         compat_ulong_t d_ino;
     475           0 :         int reclen = ALIGN(offsetof(struct compat_linux_dirent, d_name) +
     476             :                 namlen + 2, sizeof(compat_long_t));
     477           0 :         int prev_reclen;
     478             : 
     479           0 :         buf->error = verify_dirent_name(name, namlen);
     480           0 :         if (unlikely(buf->error))
     481             :                 return buf->error;
     482           0 :         buf->error = -EINVAL;        /* only used if we fail.. */
     483           0 :         if (reclen > buf->count)
     484             :                 return -EINVAL;
     485           0 :         d_ino = ino;
     486           0 :         if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
     487           0 :                 buf->error = -EOVERFLOW;
     488           0 :                 return -EOVERFLOW;
     489             :         }
     490           0 :         prev_reclen = buf->prev_reclen;
     491           0 :         if (prev_reclen && signal_pending(current))
     492             :                 return -EINTR;
     493           0 :         dirent = buf->current_dir;
     494           0 :         prev = (void __user *) dirent - prev_reclen;
     495           0 :         if (!user_write_access_begin(prev, reclen + prev_reclen))
     496           0 :                 goto efault;
     497             : 
     498           0 :         unsafe_put_user(offset, &prev->d_off, efault_end);
     499           0 :         unsafe_put_user(d_ino, &dirent->d_ino, efault_end);
     500           0 :         unsafe_put_user(reclen, &dirent->d_reclen, efault_end);
     501           0 :         unsafe_put_user(d_type, (char __user *) dirent + reclen - 1, efault_end);
     502           0 :         unsafe_copy_dirent_name(dirent->d_name, name, namlen, efault_end);
     503           0 :         user_write_access_end();
     504             : 
     505           0 :         buf->prev_reclen = reclen;
     506           0 :         buf->current_dir = (void __user *)dirent + reclen;
     507           0 :         buf->count -= reclen;
     508           0 :         return 0;
     509           0 : efault_end:
     510             :         user_write_access_end();
     511           0 : efault:
     512           0 :         buf->error = -EFAULT;
     513           0 :         return -EFAULT;
     514             : }
     515             : 
     516           0 : COMPAT_SYSCALL_DEFINE3(getdents, unsigned int, fd,
     517             :                 struct compat_linux_dirent __user *, dirent, unsigned int, count)
     518             : {
     519           0 :         struct fd f;
     520           0 :         struct compat_getdents_callback buf = {
     521             :                 .ctx.actor = compat_filldir,
     522             :                 .current_dir = dirent,
     523             :                 .count = count
     524             :         };
     525           0 :         int error;
     526             : 
     527           0 :         f = fdget_pos(fd);
     528           0 :         if (!f.file)
     529             :                 return -EBADF;
     530             : 
     531           0 :         error = iterate_dir(f.file, &buf.ctx);
     532           0 :         if (error >= 0)
     533           0 :                 error = buf.error;
     534           0 :         if (buf.prev_reclen) {
     535           0 :                 struct compat_linux_dirent __user * lastdirent;
     536           0 :                 lastdirent = (void __user *)buf.current_dir - buf.prev_reclen;
     537             : 
     538           0 :                 if (put_user(buf.ctx.pos, &lastdirent->d_off))
     539             :                         error = -EFAULT;
     540             :                 else
     541           0 :                         error = count - buf.count;
     542             :         }
     543           0 :         fdput_pos(f);
     544           0 :         return error;
     545             : }
     546             : #endif

Generated by: LCOV version 1.14