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 res = down_read_killable(&inode->i_rwsem);
43 res = down_write_killable(&inode->i_rwsem);
48 if (!IS_DEADDIR(inode)) {
49 ctx->pos = file->f_pos;
51 res = file->f_op->iterate_shared(file, ctx);
53 res = file->f_op->iterate(file, ctx);
54 file->f_pos = ctx->pos;
55 fsnotify_access(file);
59 inode_unlock_shared(inode);
65 EXPORT_SYMBOL(iterate_dir);
68 * POSIX says that a dirent name cannot contain NULL or a '/'.
70 * It's not 100% clear what we should really do in this case.
71 * The filesystem is clearly corrupted, but returning a hard
72 * error means that you now don't see any of the other names
73 * either, so that isn't a perfect alternative.
75 * And if you return an error, what error do you use? Several
76 * filesystems seem to have decided on EUCLEAN being the error
77 * code for EFSCORRUPTED, and that may be the error to use. Or
78 * just EIO, which is perhaps more obvious to users.
80 * In order to see the other file names in the directory, the
81 * caller might want to make this a "soft" error: skip the
82 * entry, and return the error at the end instead.
84 * Note that this should likely do a "memchr(name, 0, len)"
85 * check too, since that would be filesystem corruption as
86 * well. However, that case can't actually confuse user space,
87 * which has to do a strlen() on the name anyway to find the
88 * filename length, and the above "soft error" worry means
89 * that it's probably better left alone until we have that
92 static int verify_dirent_name(const char *name, int len)
96 if (memchr(name, '/', len))
102 * Traditional linux readdir() handling..
104 * "count=1" is a special case, meaning that the buffer is one
105 * dirent-structure in size and that the code can't handle more
106 * anyway. Thus the special "fillonedir()" function for that
107 * case (the low-level handlers don't need to care about this).
110 #ifdef __ARCH_WANT_OLD_READDIR
112 struct old_linux_dirent {
114 unsigned long d_offset;
115 unsigned short d_namlen;
119 struct readdir_callback {
120 struct dir_context ctx;
121 struct old_linux_dirent __user * dirent;
125 static int fillonedir(struct dir_context *ctx, const char *name, int namlen,
126 loff_t offset, u64 ino, unsigned int d_type)
128 struct readdir_callback *buf =
129 container_of(ctx, struct readdir_callback, ctx);
130 struct old_linux_dirent __user * dirent;
136 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
137 buf->result = -EOVERFLOW;
141 dirent = buf->dirent;
142 if (!access_ok(VERIFY_WRITE, dirent,
143 (unsigned long)(dirent->d_name + namlen + 1) -
144 (unsigned long)dirent))
146 if ( __put_user(d_ino, &dirent->d_ino) ||
147 __put_user(offset, &dirent->d_offset) ||
148 __put_user(namlen, &dirent->d_namlen) ||
149 __copy_to_user(dirent->d_name, name, namlen) ||
150 __put_user(0, dirent->d_name + namlen))
154 buf->result = -EFAULT;
158 SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
159 struct old_linux_dirent __user *, dirent, unsigned int, count)
162 struct fd f = fdget_pos(fd);
163 struct readdir_callback buf = {
164 .ctx.actor = fillonedir,
171 error = iterate_dir(f.file, &buf.ctx);
179 #endif /* __ARCH_WANT_OLD_READDIR */
182 * New, all-improved, singing, dancing, iBCS2-compliant getdents()
185 struct linux_dirent {
188 unsigned short d_reclen;
192 struct getdents_callback {
193 struct dir_context ctx;
194 struct linux_dirent __user * current_dir;
195 struct linux_dirent __user * previous;
200 static int filldir(struct dir_context *ctx, const char *name, int namlen,
201 loff_t offset, u64 ino, unsigned int d_type)
203 struct linux_dirent __user * dirent;
204 struct getdents_callback *buf =
205 container_of(ctx, struct getdents_callback, ctx);
207 int reclen = ALIGN(offsetof(struct linux_dirent, d_name) + namlen + 2,
210 buf->error = verify_dirent_name(name, namlen);
211 if (unlikely(buf->error))
213 buf->error = -EINVAL; /* only used if we fail.. */
214 if (reclen > buf->count)
217 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
218 buf->error = -EOVERFLOW;
221 dirent = buf->previous;
223 if (signal_pending(current))
225 if (__put_user(offset, &dirent->d_off))
228 dirent = buf->current_dir;
229 if (__put_user(d_ino, &dirent->d_ino))
231 if (__put_user(reclen, &dirent->d_reclen))
233 if (copy_to_user(dirent->d_name, name, namlen))
235 if (__put_user(0, dirent->d_name + namlen))
237 if (__put_user(d_type, (char __user *) dirent + reclen - 1))
239 buf->previous = dirent;
240 dirent = (void __user *)dirent + reclen;
241 buf->current_dir = dirent;
242 buf->count -= reclen;
245 buf->error = -EFAULT;
249 SYSCALL_DEFINE3(getdents, unsigned int, fd,
250 struct linux_dirent __user *, dirent, unsigned int, count)
253 struct linux_dirent __user * lastdirent;
254 struct getdents_callback buf = {
255 .ctx.actor = filldir,
257 .current_dir = dirent
261 if (!access_ok(VERIFY_WRITE, dirent, count))
268 error = iterate_dir(f.file, &buf.ctx);
271 lastdirent = buf.previous;
273 if (put_user(buf.ctx.pos, &lastdirent->d_off))
276 error = count - buf.count;
282 struct getdents_callback64 {
283 struct dir_context ctx;
284 struct linux_dirent64 __user * current_dir;
285 struct linux_dirent64 __user * previous;
290 static int filldir64(struct dir_context *ctx, const char *name, int namlen,
291 loff_t offset, u64 ino, unsigned int d_type)
293 struct linux_dirent64 __user *dirent;
294 struct getdents_callback64 *buf =
295 container_of(ctx, struct getdents_callback64, ctx);
296 int reclen = ALIGN(offsetof(struct linux_dirent64, d_name) + namlen + 1,
299 buf->error = verify_dirent_name(name, namlen);
300 if (unlikely(buf->error))
302 buf->error = -EINVAL; /* only used if we fail.. */
303 if (reclen > buf->count)
305 dirent = buf->previous;
307 if (signal_pending(current))
309 if (__put_user(offset, &dirent->d_off))
312 dirent = buf->current_dir;
313 if (__put_user(ino, &dirent->d_ino))
315 if (__put_user(0, &dirent->d_off))
317 if (__put_user(reclen, &dirent->d_reclen))
319 if (__put_user(d_type, &dirent->d_type))
321 if (copy_to_user(dirent->d_name, name, namlen))
323 if (__put_user(0, dirent->d_name + namlen))
325 buf->previous = dirent;
326 dirent = (void __user *)dirent + reclen;
327 buf->current_dir = dirent;
328 buf->count -= reclen;
331 buf->error = -EFAULT;
335 int ksys_getdents64(unsigned int fd, struct linux_dirent64 __user *dirent,
339 struct linux_dirent64 __user * lastdirent;
340 struct getdents_callback64 buf = {
341 .ctx.actor = filldir64,
343 .current_dir = dirent
347 if (!access_ok(VERIFY_WRITE, dirent, count))
354 error = iterate_dir(f.file, &buf.ctx);
357 lastdirent = buf.previous;
359 typeof(lastdirent->d_off) d_off = buf.ctx.pos;
360 if (__put_user(d_off, &lastdirent->d_off))
363 error = count - buf.count;
370 SYSCALL_DEFINE3(getdents64, unsigned int, fd,
371 struct linux_dirent64 __user *, dirent, unsigned int, count)
373 return ksys_getdents64(fd, dirent, count);
377 struct compat_old_linux_dirent {
378 compat_ulong_t d_ino;
379 compat_ulong_t d_offset;
380 unsigned short d_namlen;
384 struct compat_readdir_callback {
385 struct dir_context ctx;
386 struct compat_old_linux_dirent __user *dirent;
390 static int compat_fillonedir(struct dir_context *ctx, const char *name,
391 int namlen, loff_t offset, u64 ino,
394 struct compat_readdir_callback *buf =
395 container_of(ctx, struct compat_readdir_callback, ctx);
396 struct compat_old_linux_dirent __user *dirent;
397 compat_ulong_t d_ino;
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;