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