root/fs/readdir.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. iterate_dir
  2. verify_dirent_name
  3. fillonedir
  4. SYSCALL_DEFINE3
  5. filldir
  6. SYSCALL_DEFINE3
  7. filldir64
  8. ksys_getdents64
  9. SYSCALL_DEFINE3
  10. compat_fillonedir
  11. COMPAT_SYSCALL_DEFINE3
  12. compat_filldir
  13. COMPAT_SYSCALL_DEFINE3

   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 int iterate_dir(struct file *file, struct dir_context *ctx)
  41 {
  42         struct inode *inode = file_inode(file);
  43         bool shared = false;
  44         int res = -ENOTDIR;
  45         if (file->f_op->iterate_shared)
  46                 shared = true;
  47         else if (!file->f_op->iterate)
  48                 goto out;
  49 
  50         res = security_file_permission(file, MAY_READ);
  51         if (res)
  52                 goto out;
  53 
  54         if (shared)
  55                 res = down_read_killable(&inode->i_rwsem);
  56         else
  57                 res = down_write_killable(&inode->i_rwsem);
  58         if (res)
  59                 goto out;
  60 
  61         res = -ENOENT;
  62         if (!IS_DEADDIR(inode)) {
  63                 ctx->pos = file->f_pos;
  64                 if (shared)
  65                         res = file->f_op->iterate_shared(file, ctx);
  66                 else
  67                         res = file->f_op->iterate(file, ctx);
  68                 file->f_pos = ctx->pos;
  69                 fsnotify_access(file);
  70                 file_accessed(file);
  71         }
  72         if (shared)
  73                 inode_unlock_shared(inode);
  74         else
  75                 inode_unlock(inode);
  76 out:
  77         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 static int verify_dirent_name(const char *name, int len)
 111 {
 112         if (len <= 0 || len >= PATH_MAX)
 113                 return -EIO;
 114         if (memchr(name, '/', len))
 115                 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 static int fillonedir(struct dir_context *ctx, const char *name, int namlen,
 144                       loff_t offset, u64 ino, unsigned int d_type)
 145 {
 146         struct readdir_callback *buf =
 147                 container_of(ctx, struct readdir_callback, ctx);
 148         struct old_linux_dirent __user * dirent;
 149         unsigned long d_ino;
 150 
 151         if (buf->result)
 152                 return -EINVAL;
 153         d_ino = ino;
 154         if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
 155                 buf->result = -EOVERFLOW;
 156                 return -EOVERFLOW;
 157         }
 158         buf->result++;
 159         dirent = buf->dirent;
 160         if (!access_ok(dirent,
 161                         (unsigned long)(dirent->d_name + namlen + 1) -
 162                                 (unsigned long)dirent))
 163                 goto efault;
 164         if (    __put_user(d_ino, &dirent->d_ino) ||
 165                 __put_user(offset, &dirent->d_offset) ||
 166                 __put_user(namlen, &dirent->d_namlen) ||
 167                 __copy_to_user(dirent->d_name, name, namlen) ||
 168                 __put_user(0, dirent->d_name + namlen))
 169                 goto efault;
 170         return 0;
 171 efault:
 172         buf->result = -EFAULT;
 173         return -EFAULT;
 174 }
 175 
 176 SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
 177                 struct old_linux_dirent __user *, dirent, unsigned int, count)
 178 {
 179         int error;
 180         struct fd f = fdget_pos(fd);
 181         struct readdir_callback buf = {
 182                 .ctx.actor = fillonedir,
 183                 .dirent = dirent
 184         };
 185 
 186         if (!f.file)
 187                 return -EBADF;
 188 
 189         error = iterate_dir(f.file, &buf.ctx);
 190         if (buf.result)
 191                 error = buf.result;
 192 
 193         fdput_pos(f);
 194         return error;
 195 }
 196 
 197 #endif /* __ARCH_WANT_OLD_READDIR */
 198 
 199 /*
 200  * New, all-improved, singing, dancing, iBCS2-compliant getdents()
 201  * interface. 
 202  */
 203 struct linux_dirent {
 204         unsigned long   d_ino;
 205         unsigned long   d_off;
 206         unsigned short  d_reclen;
 207         char            d_name[1];
 208 };
 209 
 210 struct getdents_callback {
 211         struct dir_context ctx;
 212         struct linux_dirent __user * current_dir;
 213         int prev_reclen;
 214         int count;
 215         int error;
 216 };
 217 
 218 static int filldir(struct dir_context *ctx, const char *name, int namlen,
 219                    loff_t offset, u64 ino, unsigned int d_type)
 220 {
 221         struct linux_dirent __user *dirent, *prev;
 222         struct getdents_callback *buf =
 223                 container_of(ctx, struct getdents_callback, ctx);
 224         unsigned long d_ino;
 225         int reclen = ALIGN(offsetof(struct linux_dirent, d_name) + namlen + 2,
 226                 sizeof(long));
 227         int prev_reclen;
 228 
 229         buf->error = verify_dirent_name(name, namlen);
 230         if (unlikely(buf->error))
 231                 return buf->error;
 232         buf->error = -EINVAL;   /* only used if we fail.. */
 233         if (reclen > buf->count)
 234                 return -EINVAL;
 235         d_ino = ino;
 236         if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
 237                 buf->error = -EOVERFLOW;
 238                 return -EOVERFLOW;
 239         }
 240         prev_reclen = buf->prev_reclen;
 241         if (prev_reclen && signal_pending(current))
 242                 return -EINTR;
 243         dirent = buf->current_dir;
 244         prev = (void __user *) dirent - prev_reclen;
 245         if (!user_access_begin(prev, reclen + prev_reclen))
 246                 goto efault;
 247 
 248         /* This might be 'dirent->d_off', but if so it will get overwritten */
 249         unsafe_put_user(offset, &prev->d_off, efault_end);
 250         unsafe_put_user(d_ino, &dirent->d_ino, efault_end);
 251         unsafe_put_user(reclen, &dirent->d_reclen, efault_end);
 252         unsafe_put_user(d_type, (char __user *) dirent + reclen - 1, efault_end);
 253         unsafe_copy_dirent_name(dirent->d_name, name, namlen, efault_end);
 254         user_access_end();
 255 
 256         buf->current_dir = (void __user *)dirent + reclen;
 257         buf->prev_reclen = reclen;
 258         buf->count -= reclen;
 259         return 0;
 260 efault_end:
 261         user_access_end();
 262 efault:
 263         buf->error = -EFAULT;
 264         return -EFAULT;
 265 }
 266 
 267 SYSCALL_DEFINE3(getdents, unsigned int, fd,
 268                 struct linux_dirent __user *, dirent, unsigned int, count)
 269 {
 270         struct fd f;
 271         struct getdents_callback buf = {
 272                 .ctx.actor = filldir,
 273                 .count = count,
 274                 .current_dir = dirent
 275         };
 276         int error;
 277 
 278         if (!access_ok(dirent, count))
 279                 return -EFAULT;
 280 
 281         f = fdget_pos(fd);
 282         if (!f.file)
 283                 return -EBADF;
 284 
 285         error = iterate_dir(f.file, &buf.ctx);
 286         if (error >= 0)
 287                 error = buf.error;
 288         if (buf.prev_reclen) {
 289                 struct linux_dirent __user * lastdirent;
 290                 lastdirent = (void __user *)buf.current_dir - buf.prev_reclen;
 291 
 292                 if (put_user(buf.ctx.pos, &lastdirent->d_off))
 293                         error = -EFAULT;
 294                 else
 295                         error = count - buf.count;
 296         }
 297         fdput_pos(f);
 298         return error;
 299 }
 300 
 301 struct getdents_callback64 {
 302         struct dir_context ctx;
 303         struct linux_dirent64 __user * current_dir;
 304         int prev_reclen;
 305         int count;
 306         int error;
 307 };
 308 
 309 static int filldir64(struct dir_context *ctx, const char *name, int namlen,
 310                      loff_t offset, u64 ino, unsigned int d_type)
 311 {
 312         struct linux_dirent64 __user *dirent, *prev;
 313         struct getdents_callback64 *buf =
 314                 container_of(ctx, struct getdents_callback64, ctx);
 315         int reclen = ALIGN(offsetof(struct linux_dirent64, d_name) + namlen + 1,
 316                 sizeof(u64));
 317         int prev_reclen;
 318 
 319         buf->error = verify_dirent_name(name, namlen);
 320         if (unlikely(buf->error))
 321                 return buf->error;
 322         buf->error = -EINVAL;   /* only used if we fail.. */
 323         if (reclen > buf->count)
 324                 return -EINVAL;
 325         prev_reclen = buf->prev_reclen;
 326         if (prev_reclen && signal_pending(current))
 327                 return -EINTR;
 328         dirent = buf->current_dir;
 329         prev = (void __user *)dirent - prev_reclen;
 330         if (!user_access_begin(prev, reclen + prev_reclen))
 331                 goto efault;
 332 
 333         /* This might be 'dirent->d_off', but if so it will get overwritten */
 334         unsafe_put_user(offset, &prev->d_off, efault_end);
 335         unsafe_put_user(ino, &dirent->d_ino, efault_end);
 336         unsafe_put_user(reclen, &dirent->d_reclen, efault_end);
 337         unsafe_put_user(d_type, &dirent->d_type, efault_end);
 338         unsafe_copy_dirent_name(dirent->d_name, name, namlen, efault_end);
 339         user_access_end();
 340 
 341         buf->prev_reclen = reclen;
 342         buf->current_dir = (void __user *)dirent + reclen;
 343         buf->count -= reclen;
 344         return 0;
 345 
 346 efault_end:
 347         user_access_end();
 348 efault:
 349         buf->error = -EFAULT;
 350         return -EFAULT;
 351 }
 352 
 353 int ksys_getdents64(unsigned int fd, struct linux_dirent64 __user *dirent,
 354                     unsigned int count)
 355 {
 356         struct fd f;
 357         struct getdents_callback64 buf = {
 358                 .ctx.actor = filldir64,
 359                 .count = count,
 360                 .current_dir = dirent
 361         };
 362         int error;
 363 
 364         if (!access_ok(dirent, count))
 365                 return -EFAULT;
 366 
 367         f = fdget_pos(fd);
 368         if (!f.file)
 369                 return -EBADF;
 370 
 371         error = iterate_dir(f.file, &buf.ctx);
 372         if (error >= 0)
 373                 error = buf.error;
 374         if (buf.prev_reclen) {
 375                 struct linux_dirent64 __user * lastdirent;
 376                 typeof(lastdirent->d_off) d_off = buf.ctx.pos;
 377 
 378                 lastdirent = (void __user *) buf.current_dir - buf.prev_reclen;
 379                 if (__put_user(d_off, &lastdirent->d_off))
 380                         error = -EFAULT;
 381                 else
 382                         error = count - buf.count;
 383         }
 384         fdput_pos(f);
 385         return error;
 386 }
 387 
 388 
 389 SYSCALL_DEFINE3(getdents64, unsigned int, fd,
 390                 struct linux_dirent64 __user *, dirent, unsigned int, count)
 391 {
 392         return ksys_getdents64(fd, dirent, count);
 393 }
 394 
 395 #ifdef CONFIG_COMPAT
 396 struct compat_old_linux_dirent {
 397         compat_ulong_t  d_ino;
 398         compat_ulong_t  d_offset;
 399         unsigned short  d_namlen;
 400         char            d_name[1];
 401 };
 402 
 403 struct compat_readdir_callback {
 404         struct dir_context ctx;
 405         struct compat_old_linux_dirent __user *dirent;
 406         int result;
 407 };
 408 
 409 static int compat_fillonedir(struct dir_context *ctx, const char *name,
 410                              int namlen, loff_t offset, u64 ino,
 411                              unsigned int d_type)
 412 {
 413         struct compat_readdir_callback *buf =
 414                 container_of(ctx, struct compat_readdir_callback, ctx);
 415         struct compat_old_linux_dirent __user *dirent;
 416         compat_ulong_t d_ino;
 417 
 418         if (buf->result)
 419                 return -EINVAL;
 420         d_ino = ino;
 421         if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
 422                 buf->result = -EOVERFLOW;
 423                 return -EOVERFLOW;
 424         }
 425         buf->result++;
 426         dirent = buf->dirent;
 427         if (!access_ok(dirent,
 428                         (unsigned long)(dirent->d_name + namlen + 1) -
 429                                 (unsigned long)dirent))
 430                 goto efault;
 431         if (    __put_user(d_ino, &dirent->d_ino) ||
 432                 __put_user(offset, &dirent->d_offset) ||
 433                 __put_user(namlen, &dirent->d_namlen) ||
 434                 __copy_to_user(dirent->d_name, name, namlen) ||
 435                 __put_user(0, dirent->d_name + namlen))
 436                 goto efault;
 437         return 0;
 438 efault:
 439         buf->result = -EFAULT;
 440         return -EFAULT;
 441 }
 442 
 443 COMPAT_SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
 444                 struct compat_old_linux_dirent __user *, dirent, unsigned int, count)
 445 {
 446         int error;
 447         struct fd f = fdget_pos(fd);
 448         struct compat_readdir_callback buf = {
 449                 .ctx.actor = compat_fillonedir,
 450                 .dirent = dirent
 451         };
 452 
 453         if (!f.file)
 454                 return -EBADF;
 455 
 456         error = iterate_dir(f.file, &buf.ctx);
 457         if (buf.result)
 458                 error = buf.result;
 459 
 460         fdput_pos(f);
 461         return error;
 462 }
 463 
 464 struct compat_linux_dirent {
 465         compat_ulong_t  d_ino;
 466         compat_ulong_t  d_off;
 467         unsigned short  d_reclen;
 468         char            d_name[1];
 469 };
 470 
 471 struct compat_getdents_callback {
 472         struct dir_context ctx;
 473         struct compat_linux_dirent __user *current_dir;
 474         struct compat_linux_dirent __user *previous;
 475         int count;
 476         int error;
 477 };
 478 
 479 static int compat_filldir(struct dir_context *ctx, const char *name, int namlen,
 480                 loff_t offset, u64 ino, unsigned int d_type)
 481 {
 482         struct compat_linux_dirent __user * dirent;
 483         struct compat_getdents_callback *buf =
 484                 container_of(ctx, struct compat_getdents_callback, ctx);
 485         compat_ulong_t d_ino;
 486         int reclen = ALIGN(offsetof(struct compat_linux_dirent, d_name) +
 487                 namlen + 2, sizeof(compat_long_t));
 488 
 489         buf->error = -EINVAL;   /* only used if we fail.. */
 490         if (reclen > buf->count)
 491                 return -EINVAL;
 492         d_ino = ino;
 493         if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
 494                 buf->error = -EOVERFLOW;
 495                 return -EOVERFLOW;
 496         }
 497         dirent = buf->previous;
 498         if (dirent) {
 499                 if (signal_pending(current))
 500                         return -EINTR;
 501                 if (__put_user(offset, &dirent->d_off))
 502                         goto efault;
 503         }
 504         dirent = buf->current_dir;
 505         if (__put_user(d_ino, &dirent->d_ino))
 506                 goto efault;
 507         if (__put_user(reclen, &dirent->d_reclen))
 508                 goto efault;
 509         if (copy_to_user(dirent->d_name, name, namlen))
 510                 goto efault;
 511         if (__put_user(0, dirent->d_name + namlen))
 512                 goto efault;
 513         if (__put_user(d_type, (char  __user *) dirent + reclen - 1))
 514                 goto efault;
 515         buf->previous = dirent;
 516         dirent = (void __user *)dirent + reclen;
 517         buf->current_dir = dirent;
 518         buf->count -= reclen;
 519         return 0;
 520 efault:
 521         buf->error = -EFAULT;
 522         return -EFAULT;
 523 }
 524 
 525 COMPAT_SYSCALL_DEFINE3(getdents, unsigned int, fd,
 526                 struct compat_linux_dirent __user *, dirent, unsigned int, count)
 527 {
 528         struct fd f;
 529         struct compat_linux_dirent __user * lastdirent;
 530         struct compat_getdents_callback buf = {
 531                 .ctx.actor = compat_filldir,
 532                 .current_dir = dirent,
 533                 .count = count
 534         };
 535         int error;
 536 
 537         if (!access_ok(dirent, count))
 538                 return -EFAULT;
 539 
 540         f = fdget_pos(fd);
 541         if (!f.file)
 542                 return -EBADF;
 543 
 544         error = iterate_dir(f.file, &buf.ctx);
 545         if (error >= 0)
 546                 error = buf.error;
 547         lastdirent = buf.previous;
 548         if (lastdirent) {
 549                 if (put_user(buf.ctx.pos, &lastdirent->d_off))
 550                         error = -EFAULT;
 551                 else
 552                         error = count - buf.count;
 553         }
 554         fdput_pos(f);
 555         return error;
 556 }
 557 #endif

/* [<][>][^][v][top][bottom][index][help] */