Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  *  linux/fs/readdir.c
0004  *
0005  *  Copyright (C) 1995  Linus Torvalds
0006  */
0007 
0008 #include <linux/stddef.h>
0009 #include <linux/kernel.h>
0010 #include <linux/export.h>
0011 #include <linux/time.h>
0012 #include <linux/mm.h>
0013 #include <linux/errno.h>
0014 #include <linux/stat.h>
0015 #include <linux/file.h>
0016 #include <linux/fs.h>
0017 #include <linux/fsnotify.h>
0018 #include <linux/dirent.h>
0019 #include <linux/security.h>
0020 #include <linux/syscalls.h>
0021 #include <linux/unistd.h>
0022 #include <linux/compat.h>
0023 #include <linux/uaccess.h>
0024 
0025 #include <asm/unaligned.h>
0026 
0027 /*
0028  * Note the "unsafe_put_user() semantics: we goto a
0029  * label for errors.
0030  */
0031 #define unsafe_copy_dirent_name(_dst, _src, _len, label) do {   \
0032     char __user *dst = (_dst);              \
0033     const char *src = (_src);               \
0034     size_t len = (_len);                    \
0035     unsafe_put_user(0, dst+len, label);         \
0036     unsafe_copy_to_user(dst, src, len, label);      \
0037 } while (0)
0038 
0039 
0040 int iterate_dir(struct file *file, struct dir_context *ctx)
0041 {
0042     struct inode *inode = file_inode(file);
0043     bool shared = false;
0044     int res = -ENOTDIR;
0045     if (file->f_op->iterate_shared)
0046         shared = true;
0047     else if (!file->f_op->iterate)
0048         goto out;
0049 
0050     res = security_file_permission(file, MAY_READ);
0051     if (res)
0052         goto out;
0053 
0054     if (shared)
0055         res = down_read_killable(&inode->i_rwsem);
0056     else
0057         res = down_write_killable(&inode->i_rwsem);
0058     if (res)
0059         goto out;
0060 
0061     res = -ENOENT;
0062     if (!IS_DEADDIR(inode)) {
0063         ctx->pos = file->f_pos;
0064         if (shared)
0065             res = file->f_op->iterate_shared(file, ctx);
0066         else
0067             res = file->f_op->iterate(file, ctx);
0068         file->f_pos = ctx->pos;
0069         fsnotify_access(file);
0070         file_accessed(file);
0071     }
0072     if (shared)
0073         inode_unlock_shared(inode);
0074     else
0075         inode_unlock(inode);
0076 out:
0077     return res;
0078 }
0079 EXPORT_SYMBOL(iterate_dir);
0080 
0081 /*
0082  * POSIX says that a dirent name cannot contain NULL or a '/'.
0083  *
0084  * It's not 100% clear what we should really do in this case.
0085  * The filesystem is clearly corrupted, but returning a hard
0086  * error means that you now don't see any of the other names
0087  * either, so that isn't a perfect alternative.
0088  *
0089  * And if you return an error, what error do you use? Several
0090  * filesystems seem to have decided on EUCLEAN being the error
0091  * code for EFSCORRUPTED, and that may be the error to use. Or
0092  * just EIO, which is perhaps more obvious to users.
0093  *
0094  * In order to see the other file names in the directory, the
0095  * caller might want to make this a "soft" error: skip the
0096  * entry, and return the error at the end instead.
0097  *
0098  * Note that this should likely do a "memchr(name, 0, len)"
0099  * check too, since that would be filesystem corruption as
0100  * well. However, that case can't actually confuse user space,
0101  * which has to do a strlen() on the name anyway to find the
0102  * filename length, and the above "soft error" worry means
0103  * that it's probably better left alone until we have that
0104  * issue clarified.
0105  *
0106  * Note the PATH_MAX check - it's arbitrary but the real
0107  * kernel limit on a possible path component, not NAME_MAX,
0108  * which is the technical standard limit.
0109  */
0110 static int verify_dirent_name(const char *name, int len)
0111 {
0112     if (len <= 0 || len >= PATH_MAX)
0113         return -EIO;
0114     if (memchr(name, '/', len))
0115         return -EIO;
0116     return 0;
0117 }
0118 
0119 /*
0120  * Traditional linux readdir() handling..
0121  *
0122  * "count=1" is a special case, meaning that the buffer is one
0123  * dirent-structure in size and that the code can't handle more
0124  * anyway. Thus the special "fillonedir()" function for that
0125  * case (the low-level handlers don't need to care about this).
0126  */
0127 
0128 #ifdef __ARCH_WANT_OLD_READDIR
0129 
0130 struct old_linux_dirent {
0131     unsigned long   d_ino;
0132     unsigned long   d_offset;
0133     unsigned short  d_namlen;
0134     char        d_name[1];
0135 };
0136 
0137 struct readdir_callback {
0138     struct dir_context ctx;
0139     struct old_linux_dirent __user * dirent;
0140     int result;
0141 };
0142 
0143 static int fillonedir(struct dir_context *ctx, const char *name, int namlen,
0144               loff_t offset, u64 ino, unsigned int d_type)
0145 {
0146     struct readdir_callback *buf =
0147         container_of(ctx, struct readdir_callback, ctx);
0148     struct old_linux_dirent __user * dirent;
0149     unsigned long d_ino;
0150 
0151     if (buf->result)
0152         return -EINVAL;
0153     buf->result = verify_dirent_name(name, namlen);
0154     if (buf->result < 0)
0155         return buf->result;
0156     d_ino = ino;
0157     if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
0158         buf->result = -EOVERFLOW;
0159         return -EOVERFLOW;
0160     }
0161     buf->result++;
0162     dirent = buf->dirent;
0163     if (!user_write_access_begin(dirent,
0164             (unsigned long)(dirent->d_name + namlen + 1) -
0165                 (unsigned long)dirent))
0166         goto efault;
0167     unsafe_put_user(d_ino, &dirent->d_ino, efault_end);
0168     unsafe_put_user(offset, &dirent->d_offset, efault_end);
0169     unsafe_put_user(namlen, &dirent->d_namlen, efault_end);
0170     unsafe_copy_dirent_name(dirent->d_name, name, namlen, efault_end);
0171     user_write_access_end();
0172     return 0;
0173 efault_end:
0174     user_write_access_end();
0175 efault:
0176     buf->result = -EFAULT;
0177     return -EFAULT;
0178 }
0179 
0180 SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
0181         struct old_linux_dirent __user *, dirent, unsigned int, count)
0182 {
0183     int error;
0184     struct fd f = fdget_pos(fd);
0185     struct readdir_callback buf = {
0186         .ctx.actor = fillonedir,
0187         .dirent = dirent
0188     };
0189 
0190     if (!f.file)
0191         return -EBADF;
0192 
0193     error = iterate_dir(f.file, &buf.ctx);
0194     if (buf.result)
0195         error = buf.result;
0196 
0197     fdput_pos(f);
0198     return error;
0199 }
0200 
0201 #endif /* __ARCH_WANT_OLD_READDIR */
0202 
0203 /*
0204  * New, all-improved, singing, dancing, iBCS2-compliant getdents()
0205  * interface. 
0206  */
0207 struct linux_dirent {
0208     unsigned long   d_ino;
0209     unsigned long   d_off;
0210     unsigned short  d_reclen;
0211     char        d_name[1];
0212 };
0213 
0214 struct getdents_callback {
0215     struct dir_context ctx;
0216     struct linux_dirent __user * current_dir;
0217     int prev_reclen;
0218     int count;
0219     int error;
0220 };
0221 
0222 static int filldir(struct dir_context *ctx, const char *name, int namlen,
0223            loff_t offset, u64 ino, unsigned int d_type)
0224 {
0225     struct linux_dirent __user *dirent, *prev;
0226     struct getdents_callback *buf =
0227         container_of(ctx, struct getdents_callback, ctx);
0228     unsigned long d_ino;
0229     int reclen = ALIGN(offsetof(struct linux_dirent, d_name) + namlen + 2,
0230         sizeof(long));
0231     int prev_reclen;
0232 
0233     buf->error = verify_dirent_name(name, namlen);
0234     if (unlikely(buf->error))
0235         return buf->error;
0236     buf->error = -EINVAL;   /* only used if we fail.. */
0237     if (reclen > buf->count)
0238         return -EINVAL;
0239     d_ino = ino;
0240     if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
0241         buf->error = -EOVERFLOW;
0242         return -EOVERFLOW;
0243     }
0244     prev_reclen = buf->prev_reclen;
0245     if (prev_reclen && signal_pending(current))
0246         return -EINTR;
0247     dirent = buf->current_dir;
0248     prev = (void __user *) dirent - prev_reclen;
0249     if (!user_write_access_begin(prev, reclen + prev_reclen))
0250         goto efault;
0251 
0252     /* This might be 'dirent->d_off', but if so it will get overwritten */
0253     unsafe_put_user(offset, &prev->d_off, efault_end);
0254     unsafe_put_user(d_ino, &dirent->d_ino, efault_end);
0255     unsafe_put_user(reclen, &dirent->d_reclen, efault_end);
0256     unsafe_put_user(d_type, (char __user *) dirent + reclen - 1, efault_end);
0257     unsafe_copy_dirent_name(dirent->d_name, name, namlen, efault_end);
0258     user_write_access_end();
0259 
0260     buf->current_dir = (void __user *)dirent + reclen;
0261     buf->prev_reclen = reclen;
0262     buf->count -= reclen;
0263     return 0;
0264 efault_end:
0265     user_write_access_end();
0266 efault:
0267     buf->error = -EFAULT;
0268     return -EFAULT;
0269 }
0270 
0271 SYSCALL_DEFINE3(getdents, unsigned int, fd,
0272         struct linux_dirent __user *, dirent, unsigned int, count)
0273 {
0274     struct fd f;
0275     struct getdents_callback buf = {
0276         .ctx.actor = filldir,
0277         .count = count,
0278         .current_dir = dirent
0279     };
0280     int error;
0281 
0282     f = fdget_pos(fd);
0283     if (!f.file)
0284         return -EBADF;
0285 
0286     error = iterate_dir(f.file, &buf.ctx);
0287     if (error >= 0)
0288         error = buf.error;
0289     if (buf.prev_reclen) {
0290         struct linux_dirent __user * lastdirent;
0291         lastdirent = (void __user *)buf.current_dir - buf.prev_reclen;
0292 
0293         if (put_user(buf.ctx.pos, &lastdirent->d_off))
0294             error = -EFAULT;
0295         else
0296             error = count - buf.count;
0297     }
0298     fdput_pos(f);
0299     return error;
0300 }
0301 
0302 struct getdents_callback64 {
0303     struct dir_context ctx;
0304     struct linux_dirent64 __user * current_dir;
0305     int prev_reclen;
0306     int count;
0307     int error;
0308 };
0309 
0310 static int filldir64(struct dir_context *ctx, const char *name, int namlen,
0311              loff_t offset, u64 ino, unsigned int d_type)
0312 {
0313     struct linux_dirent64 __user *dirent, *prev;
0314     struct getdents_callback64 *buf =
0315         container_of(ctx, struct getdents_callback64, ctx);
0316     int reclen = ALIGN(offsetof(struct linux_dirent64, d_name) + namlen + 1,
0317         sizeof(u64));
0318     int prev_reclen;
0319 
0320     buf->error = verify_dirent_name(name, namlen);
0321     if (unlikely(buf->error))
0322         return buf->error;
0323     buf->error = -EINVAL;   /* only used if we fail.. */
0324     if (reclen > buf->count)
0325         return -EINVAL;
0326     prev_reclen = buf->prev_reclen;
0327     if (prev_reclen && signal_pending(current))
0328         return -EINTR;
0329     dirent = buf->current_dir;
0330     prev = (void __user *)dirent - prev_reclen;
0331     if (!user_write_access_begin(prev, reclen + prev_reclen))
0332         goto efault;
0333 
0334     /* This might be 'dirent->d_off', but if so it will get overwritten */
0335     unsafe_put_user(offset, &prev->d_off, efault_end);
0336     unsafe_put_user(ino, &dirent->d_ino, efault_end);
0337     unsafe_put_user(reclen, &dirent->d_reclen, efault_end);
0338     unsafe_put_user(d_type, &dirent->d_type, efault_end);
0339     unsafe_copy_dirent_name(dirent->d_name, name, namlen, efault_end);
0340     user_write_access_end();
0341 
0342     buf->prev_reclen = reclen;
0343     buf->current_dir = (void __user *)dirent + reclen;
0344     buf->count -= reclen;
0345     return 0;
0346 
0347 efault_end:
0348     user_write_access_end();
0349 efault:
0350     buf->error = -EFAULT;
0351     return -EFAULT;
0352 }
0353 
0354 SYSCALL_DEFINE3(getdents64, unsigned int, fd,
0355         struct linux_dirent64 __user *, dirent, unsigned int, count)
0356 {
0357     struct fd f;
0358     struct getdents_callback64 buf = {
0359         .ctx.actor = filldir64,
0360         .count = count,
0361         .current_dir = dirent
0362     };
0363     int error;
0364 
0365     f = fdget_pos(fd);
0366     if (!f.file)
0367         return -EBADF;
0368 
0369     error = iterate_dir(f.file, &buf.ctx);
0370     if (error >= 0)
0371         error = buf.error;
0372     if (buf.prev_reclen) {
0373         struct linux_dirent64 __user * lastdirent;
0374         typeof(lastdirent->d_off) d_off = buf.ctx.pos;
0375 
0376         lastdirent = (void __user *) buf.current_dir - buf.prev_reclen;
0377         if (put_user(d_off, &lastdirent->d_off))
0378             error = -EFAULT;
0379         else
0380             error = count - buf.count;
0381     }
0382     fdput_pos(f);
0383     return error;
0384 }
0385 
0386 #ifdef CONFIG_COMPAT
0387 struct compat_old_linux_dirent {
0388     compat_ulong_t  d_ino;
0389     compat_ulong_t  d_offset;
0390     unsigned short  d_namlen;
0391     char        d_name[1];
0392 };
0393 
0394 struct compat_readdir_callback {
0395     struct dir_context ctx;
0396     struct compat_old_linux_dirent __user *dirent;
0397     int result;
0398 };
0399 
0400 static int compat_fillonedir(struct dir_context *ctx, const char *name,
0401                  int namlen, loff_t offset, u64 ino,
0402                  unsigned int d_type)
0403 {
0404     struct compat_readdir_callback *buf =
0405         container_of(ctx, struct compat_readdir_callback, ctx);
0406     struct compat_old_linux_dirent __user *dirent;
0407     compat_ulong_t d_ino;
0408 
0409     if (buf->result)
0410         return -EINVAL;
0411     buf->result = verify_dirent_name(name, namlen);
0412     if (buf->result < 0)
0413         return buf->result;
0414     d_ino = ino;
0415     if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
0416         buf->result = -EOVERFLOW;
0417         return -EOVERFLOW;
0418     }
0419     buf->result++;
0420     dirent = buf->dirent;
0421     if (!user_write_access_begin(dirent,
0422             (unsigned long)(dirent->d_name + namlen + 1) -
0423                 (unsigned long)dirent))
0424         goto efault;
0425     unsafe_put_user(d_ino, &dirent->d_ino, efault_end);
0426     unsafe_put_user(offset, &dirent->d_offset, efault_end);
0427     unsafe_put_user(namlen, &dirent->d_namlen, efault_end);
0428     unsafe_copy_dirent_name(dirent->d_name, name, namlen, efault_end);
0429     user_write_access_end();
0430     return 0;
0431 efault_end:
0432     user_write_access_end();
0433 efault:
0434     buf->result = -EFAULT;
0435     return -EFAULT;
0436 }
0437 
0438 COMPAT_SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
0439         struct compat_old_linux_dirent __user *, dirent, unsigned int, count)
0440 {
0441     int error;
0442     struct fd f = fdget_pos(fd);
0443     struct compat_readdir_callback buf = {
0444         .ctx.actor = compat_fillonedir,
0445         .dirent = dirent
0446     };
0447 
0448     if (!f.file)
0449         return -EBADF;
0450 
0451     error = iterate_dir(f.file, &buf.ctx);
0452     if (buf.result)
0453         error = buf.result;
0454 
0455     fdput_pos(f);
0456     return error;
0457 }
0458 
0459 struct compat_linux_dirent {
0460     compat_ulong_t  d_ino;
0461     compat_ulong_t  d_off;
0462     unsigned short  d_reclen;
0463     char        d_name[1];
0464 };
0465 
0466 struct compat_getdents_callback {
0467     struct dir_context ctx;
0468     struct compat_linux_dirent __user *current_dir;
0469     int prev_reclen;
0470     int count;
0471     int error;
0472 };
0473 
0474 static int compat_filldir(struct dir_context *ctx, const char *name, int namlen,
0475         loff_t offset, u64 ino, unsigned int d_type)
0476 {
0477     struct compat_linux_dirent __user *dirent, *prev;
0478     struct compat_getdents_callback *buf =
0479         container_of(ctx, struct compat_getdents_callback, ctx);
0480     compat_ulong_t d_ino;
0481     int reclen = ALIGN(offsetof(struct compat_linux_dirent, d_name) +
0482         namlen + 2, sizeof(compat_long_t));
0483     int prev_reclen;
0484 
0485     buf->error = verify_dirent_name(name, namlen);
0486     if (unlikely(buf->error))
0487         return buf->error;
0488     buf->error = -EINVAL;   /* only used if we fail.. */
0489     if (reclen > buf->count)
0490         return -EINVAL;
0491     d_ino = ino;
0492     if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
0493         buf->error = -EOVERFLOW;
0494         return -EOVERFLOW;
0495     }
0496     prev_reclen = buf->prev_reclen;
0497     if (prev_reclen && signal_pending(current))
0498         return -EINTR;
0499     dirent = buf->current_dir;
0500     prev = (void __user *) dirent - prev_reclen;
0501     if (!user_write_access_begin(prev, reclen + prev_reclen))
0502         goto efault;
0503 
0504     unsafe_put_user(offset, &prev->d_off, efault_end);
0505     unsafe_put_user(d_ino, &dirent->d_ino, efault_end);
0506     unsafe_put_user(reclen, &dirent->d_reclen, efault_end);
0507     unsafe_put_user(d_type, (char __user *) dirent + reclen - 1, efault_end);
0508     unsafe_copy_dirent_name(dirent->d_name, name, namlen, efault_end);
0509     user_write_access_end();
0510 
0511     buf->prev_reclen = reclen;
0512     buf->current_dir = (void __user *)dirent + reclen;
0513     buf->count -= reclen;
0514     return 0;
0515 efault_end:
0516     user_write_access_end();
0517 efault:
0518     buf->error = -EFAULT;
0519     return -EFAULT;
0520 }
0521 
0522 COMPAT_SYSCALL_DEFINE3(getdents, unsigned int, fd,
0523         struct compat_linux_dirent __user *, dirent, unsigned int, count)
0524 {
0525     struct fd f;
0526     struct compat_getdents_callback buf = {
0527         .ctx.actor = compat_filldir,
0528         .current_dir = dirent,
0529         .count = count
0530     };
0531     int error;
0532 
0533     f = fdget_pos(fd);
0534     if (!f.file)
0535         return -EBADF;
0536 
0537     error = iterate_dir(f.file, &buf.ctx);
0538     if (error >= 0)
0539         error = buf.error;
0540     if (buf.prev_reclen) {
0541         struct compat_linux_dirent __user * lastdirent;
0542         lastdirent = (void __user *)buf.current_dir - buf.prev_reclen;
0543 
0544         if (put_user(buf.ctx.pos, &lastdirent->d_off))
0545             error = -EFAULT;
0546         else
0547             error = count - buf.count;
0548     }
0549     fdput_pos(f);
0550     return error;
0551 }
0552 #endif