0001
0002
0003
0004
0005
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
0029
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
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
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
0121
0122
0123
0124
0125
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
0202
0203
0204
0205
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;
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
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;
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
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;
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