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