1 // SPDX-License-Identifier: GPL-2.0
5 * Copyright (C) 1995 Linus Torvalds
8 #include <linux/stddef.h>
9 #include <linux/kernel.h>
10 #include <linux/export.h>
11 #include <linux/time.h>
13 #include <linux/errno.h>
14 #include <linux/stat.h>
15 #include <linux/file.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>
24 #include <linux/uaccess.h>
26 int iterate_dir(struct file *file, struct dir_context *ctx)
28 struct inode *inode = file_inode(file);
31 if (file->f_op->iterate_shared)
33 else if (!file->f_op->iterate)
36 res = security_file_permission(file, MAY_READ);
41 inode_lock_shared(inode);
43 res = down_write_killable(&inode->i_rwsem);
49 if (!IS_DEADDIR(inode)) {
50 ctx->pos = file->f_pos;
52 res = file->f_op->iterate_shared(file, ctx);
54 res = file->f_op->iterate(file, ctx);
55 file->f_pos = ctx->pos;
56 fsnotify_access(file);
60 inode_unlock_shared(inode);
66 EXPORT_SYMBOL(iterate_dir);
69 * POSIX says that a dirent name cannot contain NULL or a '/'.
71 * It's not 100% clear what we should really do in this case.
72 * The filesystem is clearly corrupted, but returning a hard
73 * error means that you now don't see any of the other names
74 * either, so that isn't a perfect alternative.
76 * And if you return an error, what error do you use? Several
77 * filesystems seem to have decided on EUCLEAN being the error
78 * code for EFSCORRUPTED, and that may be the error to use. Or
79 * just EIO, which is perhaps more obvious to users.
81 * In order to see the other file names in the directory, the
82 * caller might want to make this a "soft" error: skip the
83 * entry, and return the error at the end instead.
85 * Note that this should likely do a "memchr(name, 0, len)"
86 * check too, since that would be filesystem corruption as
87 * well. However, that case can't actually confuse user space,
88 * which has to do a strlen() on the name anyway to find the
89 * filename length, and the above "soft error" worry means
90 * that it's probably better left alone until we have that
93 static int verify_dirent_name(const char *name, int len)
97 if (memchr(name, '/', len))
103 * Traditional linux readdir() handling..
105 * "count=1" is a special case, meaning that the buffer is one
106 * dirent-structure in size and that the code can't handle more
107 * anyway. Thus the special "fillonedir()" function for that
108 * case (the low-level handlers don't need to care about this).
111 #ifdef __ARCH_WANT_OLD_READDIR
113 struct old_linux_dirent {
115 unsigned long d_offset;
116 unsigned short d_namlen;
120 struct readdir_callback {
121 struct dir_context ctx;
122 struct old_linux_dirent __user * dirent;
126 static int fillonedir(struct dir_context *ctx, const char *name, int namlen,
127 loff_t offset, u64 ino, unsigned int d_type)
129 struct readdir_callback *buf =
130 container_of(ctx, struct readdir_callback, ctx);
131 struct old_linux_dirent __user * dirent;
136 buf->result = verify_dirent_name(name, namlen);
140 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
141 buf->result = -EOVERFLOW;
145 dirent = buf->dirent;
146 if (!access_ok(VERIFY_WRITE, dirent,
147 (unsigned long)(dirent->d_name + namlen + 1) -
148 (unsigned long)dirent))
150 if ( __put_user(d_ino, &dirent->d_ino) ||
151 __put_user(offset, &dirent->d_offset) ||
152 __put_user(namlen, &dirent->d_namlen) ||
153 __copy_to_user(dirent->d_name, name, namlen) ||
154 __put_user(0, dirent->d_name + namlen))
158 buf->result = -EFAULT;
162 SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
163 struct old_linux_dirent __user *, dirent, unsigned int, count)
166 struct fd f = fdget_pos(fd);
167 struct readdir_callback buf = {
168 .ctx.actor = fillonedir,
175 error = iterate_dir(f.file, &buf.ctx);
183 #endif /* __ARCH_WANT_OLD_READDIR */
186 * New, all-improved, singing, dancing, iBCS2-compliant getdents()
189 struct linux_dirent {
192 unsigned short d_reclen;
196 struct getdents_callback {
197 struct dir_context ctx;
198 struct linux_dirent __user * current_dir;
199 struct linux_dirent __user * previous;
204 static int filldir(struct dir_context *ctx, const char *name, int namlen,
205 loff_t offset, u64 ino, unsigned int d_type)
207 struct linux_dirent __user * dirent;
208 struct getdents_callback *buf =
209 container_of(ctx, struct getdents_callback, ctx);
211 int reclen = ALIGN(offsetof(struct linux_dirent, d_name) + namlen + 2,
214 buf->error = verify_dirent_name(name, namlen);
215 if (unlikely(buf->error))
217 buf->error = -EINVAL; /* only used if we fail.. */
218 if (reclen > buf->count)
221 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
222 buf->error = -EOVERFLOW;
225 dirent = buf->previous;
227 if (signal_pending(current))
229 if (__put_user(offset, &dirent->d_off))
232 dirent = buf->current_dir;
233 if (__put_user(d_ino, &dirent->d_ino))
235 if (__put_user(reclen, &dirent->d_reclen))
237 if (copy_to_user(dirent->d_name, name, namlen))
239 if (__put_user(0, dirent->d_name + namlen))
241 if (__put_user(d_type, (char __user *) dirent + reclen - 1))
243 buf->previous = dirent;
244 dirent = (void __user *)dirent + reclen;
245 buf->current_dir = dirent;
246 buf->count -= reclen;
249 buf->error = -EFAULT;
253 SYSCALL_DEFINE3(getdents, unsigned int, fd,
254 struct linux_dirent __user *, dirent, unsigned int, count)
257 struct linux_dirent __user * lastdirent;
258 struct getdents_callback buf = {
259 .ctx.actor = filldir,
261 .current_dir = dirent
265 if (!access_ok(VERIFY_WRITE, dirent, count))
272 error = iterate_dir(f.file, &buf.ctx);
275 lastdirent = buf.previous;
277 if (put_user(buf.ctx.pos, &lastdirent->d_off))
280 error = count - buf.count;
286 struct getdents_callback64 {
287 struct dir_context ctx;
288 struct linux_dirent64 __user * current_dir;
289 struct linux_dirent64 __user * previous;
294 static int filldir64(struct dir_context *ctx, const char *name, int namlen,
295 loff_t offset, u64 ino, unsigned int d_type)
297 struct linux_dirent64 __user *dirent;
298 struct getdents_callback64 *buf =
299 container_of(ctx, struct getdents_callback64, ctx);
300 int reclen = ALIGN(offsetof(struct linux_dirent64, d_name) + namlen + 1,
303 buf->error = verify_dirent_name(name, namlen);
304 if (unlikely(buf->error))
306 buf->error = -EINVAL; /* only used if we fail.. */
307 if (reclen > buf->count)
309 dirent = buf->previous;
311 if (signal_pending(current))
313 if (__put_user(offset, &dirent->d_off))
316 dirent = buf->current_dir;
317 if (__put_user(ino, &dirent->d_ino))
319 if (__put_user(0, &dirent->d_off))
321 if (__put_user(reclen, &dirent->d_reclen))
323 if (__put_user(d_type, &dirent->d_type))
325 if (copy_to_user(dirent->d_name, name, namlen))
327 if (__put_user(0, dirent->d_name + namlen))
329 buf->previous = dirent;
330 dirent = (void __user *)dirent + reclen;
331 buf->current_dir = dirent;
332 buf->count -= reclen;
335 buf->error = -EFAULT;
339 SYSCALL_DEFINE3(getdents64, unsigned int, fd,
340 struct linux_dirent64 __user *, dirent, unsigned int, count)
343 struct linux_dirent64 __user * lastdirent;
344 struct getdents_callback64 buf = {
345 .ctx.actor = filldir64,
347 .current_dir = dirent
351 if (!access_ok(VERIFY_WRITE, dirent, count))
358 error = iterate_dir(f.file, &buf.ctx);
361 lastdirent = buf.previous;
363 typeof(lastdirent->d_off) d_off = buf.ctx.pos;
364 if (__put_user(d_off, &lastdirent->d_off))
367 error = count - buf.count;
374 struct compat_old_linux_dirent {
375 compat_ulong_t d_ino;
376 compat_ulong_t d_offset;
377 unsigned short d_namlen;
381 struct compat_readdir_callback {
382 struct dir_context ctx;
383 struct compat_old_linux_dirent __user *dirent;
387 static int compat_fillonedir(struct dir_context *ctx, const char *name,
388 int namlen, loff_t offset, u64 ino,
391 struct compat_readdir_callback *buf =
392 container_of(ctx, struct compat_readdir_callback, ctx);
393 struct compat_old_linux_dirent __user *dirent;
394 compat_ulong_t d_ino;
398 buf->result = verify_dirent_name(name, namlen);
402 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
403 buf->result = -EOVERFLOW;
407 dirent = buf->dirent;
408 if (!access_ok(VERIFY_WRITE, dirent,
409 (unsigned long)(dirent->d_name + namlen + 1) -
410 (unsigned long)dirent))
412 if ( __put_user(d_ino, &dirent->d_ino) ||
413 __put_user(offset, &dirent->d_offset) ||
414 __put_user(namlen, &dirent->d_namlen) ||
415 __copy_to_user(dirent->d_name, name, namlen) ||
416 __put_user(0, dirent->d_name + namlen))
420 buf->result = -EFAULT;
424 COMPAT_SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
425 struct compat_old_linux_dirent __user *, dirent, unsigned int, count)
428 struct fd f = fdget_pos(fd);
429 struct compat_readdir_callback buf = {
430 .ctx.actor = compat_fillonedir,
437 error = iterate_dir(f.file, &buf.ctx);
445 struct compat_linux_dirent {
446 compat_ulong_t d_ino;
447 compat_ulong_t d_off;
448 unsigned short d_reclen;
452 struct compat_getdents_callback {
453 struct dir_context ctx;
454 struct compat_linux_dirent __user *current_dir;
455 struct compat_linux_dirent __user *previous;
460 static int compat_filldir(struct dir_context *ctx, const char *name, int namlen,
461 loff_t offset, u64 ino, unsigned int d_type)
463 struct compat_linux_dirent __user * dirent;
464 struct compat_getdents_callback *buf =
465 container_of(ctx, struct compat_getdents_callback, ctx);
466 compat_ulong_t d_ino;
467 int reclen = ALIGN(offsetof(struct compat_linux_dirent, d_name) +
468 namlen + 2, sizeof(compat_long_t));
470 buf->error = -EINVAL; /* only used if we fail.. */
471 if (reclen > buf->count)
474 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
475 buf->error = -EOVERFLOW;
478 dirent = buf->previous;
480 if (signal_pending(current))
482 if (__put_user(offset, &dirent->d_off))
485 dirent = buf->current_dir;
486 if (__put_user(d_ino, &dirent->d_ino))
488 if (__put_user(reclen, &dirent->d_reclen))
490 if (copy_to_user(dirent->d_name, name, namlen))
492 if (__put_user(0, dirent->d_name + namlen))
494 if (__put_user(d_type, (char __user *) dirent + reclen - 1))
496 buf->previous = dirent;
497 dirent = (void __user *)dirent + reclen;
498 buf->current_dir = dirent;
499 buf->count -= reclen;
502 buf->error = -EFAULT;
506 COMPAT_SYSCALL_DEFINE3(getdents, unsigned int, fd,
507 struct compat_linux_dirent __user *, dirent, unsigned int, count)
510 struct compat_linux_dirent __user * lastdirent;
511 struct compat_getdents_callback buf = {
512 .ctx.actor = compat_filldir,
513 .current_dir = dirent,
518 if (!access_ok(VERIFY_WRITE, dirent, count))
525 error = iterate_dir(f.file, &buf.ctx);
528 lastdirent = buf.previous;
530 if (put_user(buf.ctx.pos, &lastdirent->d_off))
533 error = count - buf.count;