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