blob: 443270f635f43e525097ef2339a1f4572f4534d2 [file] [log] [blame]
xjb04a4022021-11-25 15:01:52 +08001// 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
24#include <linux/uaccess.h>
25
26int iterate_dir(struct file *file, struct dir_context *ctx)
27{
28 struct inode *inode = file_inode(file);
29 bool shared = false;
30 int res = -ENOTDIR;
31 if (file->f_op->iterate_shared)
32 shared = true;
33 else if (!file->f_op->iterate)
34 goto out;
35
36 res = security_file_permission(file, MAY_READ);
37 if (res)
38 goto out;
39
40 if (shared)
41 res = down_read_killable(&inode->i_rwsem);
42 else
43 res = down_write_killable(&inode->i_rwsem);
44 if (res)
45 goto out;
46
47 res = -ENOENT;
48 if (!IS_DEADDIR(inode)) {
49 ctx->pos = file->f_pos;
50 if (shared)
51 res = file->f_op->iterate_shared(file, ctx);
52 else
53 res = file->f_op->iterate(file, ctx);
54 file->f_pos = ctx->pos;
55 fsnotify_access(file);
56 file_accessed(file);
57 }
58 if (shared)
59 inode_unlock_shared(inode);
60 else
61 inode_unlock(inode);
62out:
63 return res;
64}
65EXPORT_SYMBOL(iterate_dir);
66
67/*
68 * POSIX says that a dirent name cannot contain NULL or a '/'.
69 *
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.
74 *
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.
79 *
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.
83 *
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
90 * issue clarified.
91 */
92static int verify_dirent_name(const char *name, int len)
93{
94 if (!len)
95 return -EIO;
96 if (memchr(name, '/', len))
97 return -EIO;
98 return 0;
99}
100
101/*
102 * Traditional linux readdir() handling..
103 *
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).
108 */
109
110#ifdef __ARCH_WANT_OLD_READDIR
111
112struct old_linux_dirent {
113 unsigned long d_ino;
114 unsigned long d_offset;
115 unsigned short d_namlen;
116 char d_name[1];
117};
118
119struct readdir_callback {
120 struct dir_context ctx;
121 struct old_linux_dirent __user * dirent;
122 int result;
123};
124
125static int fillonedir(struct dir_context *ctx, const char *name, int namlen,
126 loff_t offset, u64 ino, unsigned int d_type)
127{
128 struct readdir_callback *buf =
129 container_of(ctx, struct readdir_callback, ctx);
130 struct old_linux_dirent __user * dirent;
131 unsigned long d_ino;
132
133 if (buf->result)
134 return -EINVAL;
135 d_ino = ino;
136 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
137 buf->result = -EOVERFLOW;
138 return -EOVERFLOW;
139 }
140 buf->result++;
141 dirent = buf->dirent;
142 if (!access_ok(VERIFY_WRITE, dirent,
143 (unsigned long)(dirent->d_name + namlen + 1) -
144 (unsigned long)dirent))
145 goto efault;
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))
151 goto efault;
152 return 0;
153efault:
154 buf->result = -EFAULT;
155 return -EFAULT;
156}
157
158SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
159 struct old_linux_dirent __user *, dirent, unsigned int, count)
160{
161 int error;
162 struct fd f = fdget_pos(fd);
163 struct readdir_callback buf = {
164 .ctx.actor = fillonedir,
165 .dirent = dirent
166 };
167
168 if (!f.file)
169 return -EBADF;
170
171 error = iterate_dir(f.file, &buf.ctx);
172 if (buf.result)
173 error = buf.result;
174
175 fdput_pos(f);
176 return error;
177}
178
179#endif /* __ARCH_WANT_OLD_READDIR */
180
181/*
182 * New, all-improved, singing, dancing, iBCS2-compliant getdents()
183 * interface.
184 */
185struct linux_dirent {
186 unsigned long d_ino;
187 unsigned long d_off;
188 unsigned short d_reclen;
189 char d_name[1];
190};
191
192struct getdents_callback {
193 struct dir_context ctx;
194 struct linux_dirent __user * current_dir;
195 struct linux_dirent __user * previous;
196 int count;
197 int error;
198};
199
200static int filldir(struct dir_context *ctx, const char *name, int namlen,
201 loff_t offset, u64 ino, unsigned int d_type)
202{
203 struct linux_dirent __user * dirent;
204 struct getdents_callback *buf =
205 container_of(ctx, struct getdents_callback, ctx);
206 unsigned long d_ino;
207 int reclen = ALIGN(offsetof(struct linux_dirent, d_name) + namlen + 2,
208 sizeof(long));
209
210 buf->error = verify_dirent_name(name, namlen);
211 if (unlikely(buf->error))
212 return buf->error;
213 buf->error = -EINVAL; /* only used if we fail.. */
214 if (reclen > buf->count)
215 return -EINVAL;
216 d_ino = ino;
217 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
218 buf->error = -EOVERFLOW;
219 return -EOVERFLOW;
220 }
221 dirent = buf->previous;
222 if (dirent) {
223 if (signal_pending(current))
224 return -EINTR;
225 if (__put_user(offset, &dirent->d_off))
226 goto efault;
227 }
228 dirent = buf->current_dir;
229 if (__put_user(d_ino, &dirent->d_ino))
230 goto efault;
231 if (__put_user(reclen, &dirent->d_reclen))
232 goto efault;
233 if (copy_to_user(dirent->d_name, name, namlen))
234 goto efault;
235 if (__put_user(0, dirent->d_name + namlen))
236 goto efault;
237 if (__put_user(d_type, (char __user *) dirent + reclen - 1))
238 goto efault;
239 buf->previous = dirent;
240 dirent = (void __user *)dirent + reclen;
241 buf->current_dir = dirent;
242 buf->count -= reclen;
243 return 0;
244efault:
245 buf->error = -EFAULT;
246 return -EFAULT;
247}
248
249SYSCALL_DEFINE3(getdents, unsigned int, fd,
250 struct linux_dirent __user *, dirent, unsigned int, count)
251{
252 struct fd f;
253 struct linux_dirent __user * lastdirent;
254 struct getdents_callback buf = {
255 .ctx.actor = filldir,
256 .count = count,
257 .current_dir = dirent
258 };
259 int error;
260
261 if (!access_ok(VERIFY_WRITE, dirent, count))
262 return -EFAULT;
263
264 f = fdget_pos(fd);
265 if (!f.file)
266 return -EBADF;
267
268 error = iterate_dir(f.file, &buf.ctx);
269 if (error >= 0)
270 error = buf.error;
271 lastdirent = buf.previous;
272 if (lastdirent) {
273 if (put_user(buf.ctx.pos, &lastdirent->d_off))
274 error = -EFAULT;
275 else
276 error = count - buf.count;
277 }
278 fdput_pos(f);
279 return error;
280}
281
282struct getdents_callback64 {
283 struct dir_context ctx;
284 struct linux_dirent64 __user * current_dir;
285 struct linux_dirent64 __user * previous;
286 int count;
287 int error;
288};
289
290static int filldir64(struct dir_context *ctx, const char *name, int namlen,
291 loff_t offset, u64 ino, unsigned int d_type)
292{
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,
297 sizeof(u64));
298
299 buf->error = verify_dirent_name(name, namlen);
300 if (unlikely(buf->error))
301 return buf->error;
302 buf->error = -EINVAL; /* only used if we fail.. */
303 if (reclen > buf->count)
304 return -EINVAL;
305 dirent = buf->previous;
306 if (dirent) {
307 if (signal_pending(current))
308 return -EINTR;
309 if (__put_user(offset, &dirent->d_off))
310 goto efault;
311 }
312 dirent = buf->current_dir;
313 if (__put_user(ino, &dirent->d_ino))
314 goto efault;
315 if (__put_user(0, &dirent->d_off))
316 goto efault;
317 if (__put_user(reclen, &dirent->d_reclen))
318 goto efault;
319 if (__put_user(d_type, &dirent->d_type))
320 goto efault;
321 if (copy_to_user(dirent->d_name, name, namlen))
322 goto efault;
323 if (__put_user(0, dirent->d_name + namlen))
324 goto efault;
325 buf->previous = dirent;
326 dirent = (void __user *)dirent + reclen;
327 buf->current_dir = dirent;
328 buf->count -= reclen;
329 return 0;
330efault:
331 buf->error = -EFAULT;
332 return -EFAULT;
333}
334
335int ksys_getdents64(unsigned int fd, struct linux_dirent64 __user *dirent,
336 unsigned int count)
337{
338 struct fd f;
339 struct linux_dirent64 __user * lastdirent;
340 struct getdents_callback64 buf = {
341 .ctx.actor = filldir64,
342 .count = count,
343 .current_dir = dirent
344 };
345 int error;
346
347 if (!access_ok(VERIFY_WRITE, dirent, count))
348 return -EFAULT;
349
350 f = fdget_pos(fd);
351 if (!f.file)
352 return -EBADF;
353
354 error = iterate_dir(f.file, &buf.ctx);
355 if (error >= 0)
356 error = buf.error;
357 lastdirent = buf.previous;
358 if (lastdirent) {
359 typeof(lastdirent->d_off) d_off = buf.ctx.pos;
360 if (__put_user(d_off, &lastdirent->d_off))
361 error = -EFAULT;
362 else
363 error = count - buf.count;
364 }
365 fdput_pos(f);
366 return error;
367}
368
369
370SYSCALL_DEFINE3(getdents64, unsigned int, fd,
371 struct linux_dirent64 __user *, dirent, unsigned int, count)
372{
373 return ksys_getdents64(fd, dirent, count);
374}
375
376#ifdef CONFIG_COMPAT
377struct compat_old_linux_dirent {
378 compat_ulong_t d_ino;
379 compat_ulong_t d_offset;
380 unsigned short d_namlen;
381 char d_name[1];
382};
383
384struct compat_readdir_callback {
385 struct dir_context ctx;
386 struct compat_old_linux_dirent __user *dirent;
387 int result;
388};
389
390static int compat_fillonedir(struct dir_context *ctx, const char *name,
391 int namlen, loff_t offset, u64 ino,
392 unsigned int d_type)
393{
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;
398
399 if (buf->result)
400 return -EINVAL;
401 d_ino = ino;
402 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
403 buf->result = -EOVERFLOW;
404 return -EOVERFLOW;
405 }
406 buf->result++;
407 dirent = buf->dirent;
408 if (!access_ok(VERIFY_WRITE, dirent,
409 (unsigned long)(dirent->d_name + namlen + 1) -
410 (unsigned long)dirent))
411 goto efault;
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))
417 goto efault;
418 return 0;
419efault:
420 buf->result = -EFAULT;
421 return -EFAULT;
422}
423
424COMPAT_SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
425 struct compat_old_linux_dirent __user *, dirent, unsigned int, count)
426{
427 int error;
428 struct fd f = fdget_pos(fd);
429 struct compat_readdir_callback buf = {
430 .ctx.actor = compat_fillonedir,
431 .dirent = dirent
432 };
433
434 if (!f.file)
435 return -EBADF;
436
437 error = iterate_dir(f.file, &buf.ctx);
438 if (buf.result)
439 error = buf.result;
440
441 fdput_pos(f);
442 return error;
443}
444
445struct compat_linux_dirent {
446 compat_ulong_t d_ino;
447 compat_ulong_t d_off;
448 unsigned short d_reclen;
449 char d_name[1];
450};
451
452struct compat_getdents_callback {
453 struct dir_context ctx;
454 struct compat_linux_dirent __user *current_dir;
455 struct compat_linux_dirent __user *previous;
456 int count;
457 int error;
458};
459
460static int compat_filldir(struct dir_context *ctx, const char *name, int namlen,
461 loff_t offset, u64 ino, unsigned int d_type)
462{
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));
469
470 buf->error = -EINVAL; /* only used if we fail.. */
471 if (reclen > buf->count)
472 return -EINVAL;
473 d_ino = ino;
474 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
475 buf->error = -EOVERFLOW;
476 return -EOVERFLOW;
477 }
478 dirent = buf->previous;
479 if (dirent) {
480 if (signal_pending(current))
481 return -EINTR;
482 if (__put_user(offset, &dirent->d_off))
483 goto efault;
484 }
485 dirent = buf->current_dir;
486 if (__put_user(d_ino, &dirent->d_ino))
487 goto efault;
488 if (__put_user(reclen, &dirent->d_reclen))
489 goto efault;
490 if (copy_to_user(dirent->d_name, name, namlen))
491 goto efault;
492 if (__put_user(0, dirent->d_name + namlen))
493 goto efault;
494 if (__put_user(d_type, (char __user *) dirent + reclen - 1))
495 goto efault;
496 buf->previous = dirent;
497 dirent = (void __user *)dirent + reclen;
498 buf->current_dir = dirent;
499 buf->count -= reclen;
500 return 0;
501efault:
502 buf->error = -EFAULT;
503 return -EFAULT;
504}
505
506COMPAT_SYSCALL_DEFINE3(getdents, unsigned int, fd,
507 struct compat_linux_dirent __user *, dirent, unsigned int, count)
508{
509 struct fd f;
510 struct compat_linux_dirent __user * lastdirent;
511 struct compat_getdents_callback buf = {
512 .ctx.actor = compat_filldir,
513 .current_dir = dirent,
514 .count = count
515 };
516 int error;
517
518 if (!access_ok(VERIFY_WRITE, dirent, count))
519 return -EFAULT;
520
521 f = fdget_pos(fd);
522 if (!f.file)
523 return -EBADF;
524
525 error = iterate_dir(f.file, &buf.ctx);
526 if (error >= 0)
527 error = buf.error;
528 lastdirent = buf.previous;
529 if (lastdirent) {
530 if (put_user(buf.ctx.pos, &lastdirent->d_off))
531 error = -EFAULT;
532 else
533 error = count - buf.count;
534 }
535 fdput_pos(f);
536 return error;
537}
538#endif