]> git.proxmox.com Git - mirror_ubuntu-focal-kernel.git/blame - fs/readdir.c
NFSv4: Handle case where the lookup of a directory fails
[mirror_ubuntu-focal-kernel.git] / fs / readdir.c
CommitLineData
b2441318 1// SPDX-License-Identifier: GPL-2.0
1da177e4
LT
2/*
3 * linux/fs/readdir.c
4 *
5 * Copyright (C) 1995 Linus Torvalds
6 */
7
85c9fe8f 8#include <linux/stddef.h>
022a1692 9#include <linux/kernel.h>
630d9c47 10#include <linux/export.h>
1da177e4
LT
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>
1da177e4 16#include <linux/fs.h>
d4c7cf6c 17#include <linux/fsnotify.h>
1da177e4
LT
18#include <linux/dirent.h>
19#include <linux/security.h>
20#include <linux/syscalls.h>
21#include <linux/unistd.h>
0460b2a2 22#include <linux/compat.h>
7c0f6ba6 23#include <linux/uaccess.h>
1da177e4 24
9f79b78e
LT
25#include <asm/unaligned.h>
26
27/*
28 * Note the "unsafe_put_user() semantics: we goto a
29 * label for errors.
9f79b78e
LT
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); \
c512c691
LT
35 unsafe_put_user(0, dst+len, label); \
36 unsafe_copy_to_user(dst, src, len, label); \
9f79b78e
LT
37} while (0)
38
39
5c0ba4e0 40int iterate_dir(struct file *file, struct dir_context *ctx)
1da177e4 41{
496ad9aa 42 struct inode *inode = file_inode(file);
61922694 43 bool shared = false;
1da177e4 44 int res = -ENOTDIR;
61922694
AV
45 if (file->f_op->iterate_shared)
46 shared = true;
47 else if (!file->f_op->iterate)
1da177e4
LT
48 goto out;
49
50 res = security_file_permission(file, MAY_READ);
51 if (res)
52 goto out;
53
0dc208b5
KT
54 if (shared)
55 res = down_read_killable(&inode->i_rwsem);
56 else
00235411 57 res = down_write_killable(&inode->i_rwsem);
0dc208b5
KT
58 if (res)
59 goto out;
da784511 60
1da177e4
LT
61 res = -ENOENT;
62 if (!IS_DEADDIR(inode)) {
2233f31a 63 ctx->pos = file->f_pos;
61922694
AV
64 if (shared)
65 res = file->f_op->iterate_shared(file, ctx);
66 else
67 res = file->f_op->iterate(file, ctx);
2233f31a 68 file->f_pos = ctx->pos;
d4c7cf6c 69 fsnotify_access(file);
1da177e4
LT
70 file_accessed(file);
71 }
61922694
AV
72 if (shared)
73 inode_unlock_shared(inode);
74 else
75 inode_unlock(inode);
1da177e4
LT
76out:
77 return res;
78}
5c0ba4e0 79EXPORT_SYMBOL(iterate_dir);
1da177e4 80
8a23eb80
LT
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.
8d76fdd8
LT
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.
8a23eb80
LT
109 */
110static int verify_dirent_name(const char *name, int len)
111{
8d76fdd8 112 if (len <= 0 || len >= PATH_MAX)
8a23eb80 113 return -EIO;
b9959c7a 114 if (memchr(name, '/', len))
8a23eb80
LT
115 return -EIO;
116 return 0;
117}
118
1da177e4
LT
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 */
1da177e4
LT
127
128#ifdef __ARCH_WANT_OLD_READDIR
129
130struct 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
137struct readdir_callback {
5c0ba4e0 138 struct dir_context ctx;
1da177e4
LT
139 struct old_linux_dirent __user * dirent;
140 int result;
141};
142
ac7576f4
MS
143static int fillonedir(struct dir_context *ctx, const char *name, int namlen,
144 loff_t offset, u64 ino, unsigned int d_type)
1da177e4 145{
ac7576f4
MS
146 struct readdir_callback *buf =
147 container_of(ctx, struct readdir_callback, ctx);
1da177e4 148 struct old_linux_dirent __user * dirent;
afefdbb2 149 unsigned long d_ino;
1da177e4
LT
150
151 if (buf->result)
152 return -EINVAL;
43eb711c
LT
153 buf->result = verify_dirent_name(name, namlen);
154 if (buf->result < 0)
155 return buf->result;
afefdbb2 156 d_ino = ino;
8f3f655d
AV
157 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
158 buf->result = -EOVERFLOW;
afefdbb2 159 return -EOVERFLOW;
8f3f655d 160 }
1da177e4
LT
161 buf->result++;
162 dirent = buf->dirent;
96d4f267 163 if (!access_ok(dirent,
1da177e4
LT
164 (unsigned long)(dirent->d_name + namlen + 1) -
165 (unsigned long)dirent))
166 goto efault;
afefdbb2 167 if ( __put_user(d_ino, &dirent->d_ino) ||
1da177e4
LT
168 __put_user(offset, &dirent->d_offset) ||
169 __put_user(namlen, &dirent->d_namlen) ||
170 __copy_to_user(dirent->d_name, name, namlen) ||
171 __put_user(0, dirent->d_name + namlen))
172 goto efault;
173 return 0;
174efault:
175 buf->result = -EFAULT;
176 return -EFAULT;
177}
178
d4e82042
HC
179SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
180 struct old_linux_dirent __user *, dirent, unsigned int, count)
1da177e4
LT
181{
182 int error;
63b6df14 183 struct fd f = fdget_pos(fd);
ac6614b7
AV
184 struct readdir_callback buf = {
185 .ctx.actor = fillonedir,
186 .dirent = dirent
187 };
1da177e4 188
2903ff01 189 if (!f.file)
863ced7f 190 return -EBADF;
1da177e4 191
5c0ba4e0 192 error = iterate_dir(f.file, &buf.ctx);
53c9c5c0 193 if (buf.result)
1da177e4
LT
194 error = buf.result;
195
63b6df14 196 fdput_pos(f);
1da177e4
LT
197 return error;
198}
199
200#endif /* __ARCH_WANT_OLD_READDIR */
201
202/*
203 * New, all-improved, singing, dancing, iBCS2-compliant getdents()
204 * interface.
205 */
206struct linux_dirent {
207 unsigned long d_ino;
208 unsigned long d_off;
209 unsigned short d_reclen;
210 char d_name[1];
211};
212
213struct getdents_callback {
5c0ba4e0 214 struct dir_context ctx;
1da177e4 215 struct linux_dirent __user * current_dir;
98e51dc7 216 int prev_reclen;
1da177e4
LT
217 int count;
218 int error;
219};
220
ac7576f4
MS
221static int filldir(struct dir_context *ctx, const char *name, int namlen,
222 loff_t offset, u64 ino, unsigned int d_type)
1da177e4 223{
98e51dc7 224 struct linux_dirent __user *dirent, *prev;
ac7576f4
MS
225 struct getdents_callback *buf =
226 container_of(ctx, struct getdents_callback, ctx);
afefdbb2 227 unsigned long d_ino;
85c9fe8f
KW
228 int reclen = ALIGN(offsetof(struct linux_dirent, d_name) + namlen + 2,
229 sizeof(long));
98e51dc7 230 int prev_reclen;
1da177e4 231
8a23eb80
LT
232 buf->error = verify_dirent_name(name, namlen);
233 if (unlikely(buf->error))
234 return buf->error;
1da177e4
LT
235 buf->error = -EINVAL; /* only used if we fail.. */
236 if (reclen > buf->count)
237 return -EINVAL;
afefdbb2 238 d_ino = ino;
8f3f655d
AV
239 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
240 buf->error = -EOVERFLOW;
afefdbb2 241 return -EOVERFLOW;
8f3f655d 242 }
98e51dc7
LT
243 prev_reclen = buf->prev_reclen;
244 if (prev_reclen && signal_pending(current))
9f79b78e 245 return -EINTR;
9f79b78e 246 dirent = buf->current_dir;
98e51dc7
LT
247 prev = (void __user *) dirent - prev_reclen;
248 if (!user_access_begin(prev, reclen + prev_reclen))
249 goto efault;
250
251 /* This might be 'dirent->d_off', but if so it will get overwritten */
252 unsafe_put_user(offset, &prev->d_off, efault_end);
9f79b78e
LT
253 unsafe_put_user(d_ino, &dirent->d_ino, efault_end);
254 unsafe_put_user(reclen, &dirent->d_reclen, efault_end);
255 unsafe_put_user(d_type, (char __user *) dirent + reclen - 1, efault_end);
256 unsafe_copy_dirent_name(dirent->d_name, name, namlen, efault_end);
257 user_access_end();
258
98e51dc7
LT
259 buf->current_dir = (void __user *)dirent + reclen;
260 buf->prev_reclen = reclen;
1da177e4
LT
261 buf->count -= reclen;
262 return 0;
9f79b78e
LT
263efault_end:
264 user_access_end();
1da177e4
LT
265efault:
266 buf->error = -EFAULT;
267 return -EFAULT;
268}
269
20f37034
HC
270SYSCALL_DEFINE3(getdents, unsigned int, fd,
271 struct linux_dirent __user *, dirent, unsigned int, count)
1da177e4 272{
2903ff01 273 struct fd f;
ac6614b7
AV
274 struct getdents_callback buf = {
275 .ctx.actor = filldir,
276 .count = count,
277 .current_dir = dirent
278 };
1da177e4
LT
279 int error;
280
96d4f267 281 if (!access_ok(dirent, count))
863ced7f 282 return -EFAULT;
1da177e4 283
63b6df14 284 f = fdget_pos(fd);
2903ff01 285 if (!f.file)
863ced7f 286 return -EBADF;
1da177e4 287
5c0ba4e0 288 error = iterate_dir(f.file, &buf.ctx);
53c9c5c0
AV
289 if (error >= 0)
290 error = buf.error;
98e51dc7
LT
291 if (buf.prev_reclen) {
292 struct linux_dirent __user * lastdirent;
293 lastdirent = (void __user *)buf.current_dir - buf.prev_reclen;
294
bb6f619b 295 if (put_user(buf.ctx.pos, &lastdirent->d_off))
1da177e4
LT
296 error = -EFAULT;
297 else
298 error = count - buf.count;
299 }
63b6df14 300 fdput_pos(f);
1da177e4
LT
301 return error;
302}
303
1da177e4 304struct getdents_callback64 {
5c0ba4e0 305 struct dir_context ctx;
1da177e4 306 struct linux_dirent64 __user * current_dir;
98e51dc7 307 int prev_reclen;
1da177e4
LT
308 int count;
309 int error;
310};
311
ac7576f4
MS
312static int filldir64(struct dir_context *ctx, const char *name, int namlen,
313 loff_t offset, u64 ino, unsigned int d_type)
1da177e4 314{
98e51dc7 315 struct linux_dirent64 __user *dirent, *prev;
ac7576f4
MS
316 struct getdents_callback64 *buf =
317 container_of(ctx, struct getdents_callback64, ctx);
85c9fe8f
KW
318 int reclen = ALIGN(offsetof(struct linux_dirent64, d_name) + namlen + 1,
319 sizeof(u64));
98e51dc7 320 int prev_reclen;
1da177e4 321
8a23eb80
LT
322 buf->error = verify_dirent_name(name, namlen);
323 if (unlikely(buf->error))
324 return buf->error;
1da177e4
LT
325 buf->error = -EINVAL; /* only used if we fail.. */
326 if (reclen > buf->count)
327 return -EINVAL;
98e51dc7
LT
328 prev_reclen = buf->prev_reclen;
329 if (prev_reclen && signal_pending(current))
9f79b78e 330 return -EINTR;
9f79b78e 331 dirent = buf->current_dir;
98e51dc7
LT
332 prev = (void __user *)dirent - prev_reclen;
333 if (!user_access_begin(prev, reclen + prev_reclen))
334 goto efault;
335
336 /* This might be 'dirent->d_off', but if so it will get overwritten */
337 unsafe_put_user(offset, &prev->d_off, efault_end);
9f79b78e
LT
338 unsafe_put_user(ino, &dirent->d_ino, efault_end);
339 unsafe_put_user(reclen, &dirent->d_reclen, efault_end);
340 unsafe_put_user(d_type, &dirent->d_type, efault_end);
341 unsafe_copy_dirent_name(dirent->d_name, name, namlen, efault_end);
342 user_access_end();
343
98e51dc7
LT
344 buf->prev_reclen = reclen;
345 buf->current_dir = (void __user *)dirent + reclen;
1da177e4
LT
346 buf->count -= reclen;
347 return 0;
98e51dc7 348
9f79b78e
LT
349efault_end:
350 user_access_end();
1da177e4
LT
351efault:
352 buf->error = -EFAULT;
353 return -EFAULT;
354}
355
454dab3f
DB
356int ksys_getdents64(unsigned int fd, struct linux_dirent64 __user *dirent,
357 unsigned int count)
1da177e4 358{
2903ff01 359 struct fd f;
ac6614b7
AV
360 struct getdents_callback64 buf = {
361 .ctx.actor = filldir64,
362 .count = count,
363 .current_dir = dirent
364 };
1da177e4
LT
365 int error;
366
96d4f267 367 if (!access_ok(dirent, count))
863ced7f 368 return -EFAULT;
1da177e4 369
63b6df14 370 f = fdget_pos(fd);
2903ff01 371 if (!f.file)
863ced7f 372 return -EBADF;
1da177e4 373
5c0ba4e0 374 error = iterate_dir(f.file, &buf.ctx);
53c9c5c0
AV
375 if (error >= 0)
376 error = buf.error;
98e51dc7
LT
377 if (buf.prev_reclen) {
378 struct linux_dirent64 __user * lastdirent;
bb6f619b 379 typeof(lastdirent->d_off) d_off = buf.ctx.pos;
98e51dc7
LT
380
381 lastdirent = (void __user *) buf.current_dir - buf.prev_reclen;
1da177e4 382 if (__put_user(d_off, &lastdirent->d_off))
53c9c5c0
AV
383 error = -EFAULT;
384 else
385 error = count - buf.count;
1da177e4 386 }
63b6df14 387 fdput_pos(f);
1da177e4
LT
388 return error;
389}
0460b2a2 390
454dab3f
DB
391
392SYSCALL_DEFINE3(getdents64, unsigned int, fd,
393 struct linux_dirent64 __user *, dirent, unsigned int, count)
394{
395 return ksys_getdents64(fd, dirent, count);
396}
397
0460b2a2
AV
398#ifdef CONFIG_COMPAT
399struct compat_old_linux_dirent {
400 compat_ulong_t d_ino;
401 compat_ulong_t d_offset;
402 unsigned short d_namlen;
403 char d_name[1];
404};
405
406struct compat_readdir_callback {
407 struct dir_context ctx;
408 struct compat_old_linux_dirent __user *dirent;
409 int result;
410};
411
412static int compat_fillonedir(struct dir_context *ctx, const char *name,
413 int namlen, loff_t offset, u64 ino,
414 unsigned int d_type)
415{
416 struct compat_readdir_callback *buf =
417 container_of(ctx, struct compat_readdir_callback, ctx);
418 struct compat_old_linux_dirent __user *dirent;
419 compat_ulong_t d_ino;
420
421 if (buf->result)
422 return -EINVAL;
43eb711c
LT
423 buf->result = verify_dirent_name(name, namlen);
424 if (buf->result < 0)
425 return buf->result;
0460b2a2
AV
426 d_ino = ino;
427 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
428 buf->result = -EOVERFLOW;
429 return -EOVERFLOW;
430 }
431 buf->result++;
432 dirent = buf->dirent;
96d4f267 433 if (!access_ok(dirent,
0460b2a2
AV
434 (unsigned long)(dirent->d_name + namlen + 1) -
435 (unsigned long)dirent))
436 goto efault;
437 if ( __put_user(d_ino, &dirent->d_ino) ||
438 __put_user(offset, &dirent->d_offset) ||
439 __put_user(namlen, &dirent->d_namlen) ||
440 __copy_to_user(dirent->d_name, name, namlen) ||
441 __put_user(0, dirent->d_name + namlen))
442 goto efault;
443 return 0;
444efault:
445 buf->result = -EFAULT;
446 return -EFAULT;
447}
448
449COMPAT_SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
450 struct compat_old_linux_dirent __user *, dirent, unsigned int, count)
451{
452 int error;
453 struct fd f = fdget_pos(fd);
454 struct compat_readdir_callback buf = {
455 .ctx.actor = compat_fillonedir,
456 .dirent = dirent
457 };
458
459 if (!f.file)
460 return -EBADF;
461
462 error = iterate_dir(f.file, &buf.ctx);
463 if (buf.result)
464 error = buf.result;
465
466 fdput_pos(f);
467 return error;
468}
469
470struct compat_linux_dirent {
471 compat_ulong_t d_ino;
472 compat_ulong_t d_off;
473 unsigned short d_reclen;
474 char d_name[1];
475};
476
477struct compat_getdents_callback {
478 struct dir_context ctx;
479 struct compat_linux_dirent __user *current_dir;
480 struct compat_linux_dirent __user *previous;
481 int count;
482 int error;
483};
484
485static int compat_filldir(struct dir_context *ctx, const char *name, int namlen,
486 loff_t offset, u64 ino, unsigned int d_type)
487{
488 struct compat_linux_dirent __user * dirent;
489 struct compat_getdents_callback *buf =
490 container_of(ctx, struct compat_getdents_callback, ctx);
491 compat_ulong_t d_ino;
492 int reclen = ALIGN(offsetof(struct compat_linux_dirent, d_name) +
493 namlen + 2, sizeof(compat_long_t));
494
495 buf->error = -EINVAL; /* only used if we fail.. */
496 if (reclen > buf->count)
497 return -EINVAL;
498 d_ino = ino;
499 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
500 buf->error = -EOVERFLOW;
501 return -EOVERFLOW;
502 }
503 dirent = buf->previous;
504 if (dirent) {
505 if (signal_pending(current))
506 return -EINTR;
507 if (__put_user(offset, &dirent->d_off))
508 goto efault;
509 }
510 dirent = buf->current_dir;
511 if (__put_user(d_ino, &dirent->d_ino))
512 goto efault;
513 if (__put_user(reclen, &dirent->d_reclen))
514 goto efault;
515 if (copy_to_user(dirent->d_name, name, namlen))
516 goto efault;
517 if (__put_user(0, dirent->d_name + namlen))
518 goto efault;
519 if (__put_user(d_type, (char __user *) dirent + reclen - 1))
520 goto efault;
521 buf->previous = dirent;
522 dirent = (void __user *)dirent + reclen;
523 buf->current_dir = dirent;
524 buf->count -= reclen;
525 return 0;
526efault:
527 buf->error = -EFAULT;
528 return -EFAULT;
529}
530
531COMPAT_SYSCALL_DEFINE3(getdents, unsigned int, fd,
532 struct compat_linux_dirent __user *, dirent, unsigned int, count)
533{
534 struct fd f;
535 struct compat_linux_dirent __user * lastdirent;
536 struct compat_getdents_callback buf = {
537 .ctx.actor = compat_filldir,
538 .current_dir = dirent,
539 .count = count
540 };
541 int error;
542
96d4f267 543 if (!access_ok(dirent, count))
0460b2a2
AV
544 return -EFAULT;
545
546 f = fdget_pos(fd);
547 if (!f.file)
548 return -EBADF;
549
550 error = iterate_dir(f.file, &buf.ctx);
551 if (error >= 0)
552 error = buf.error;
553 lastdirent = buf.previous;
554 if (lastdirent) {
555 if (put_user(buf.ctx.pos, &lastdirent->d_off))
556 error = -EFAULT;
557 else
558 error = count - buf.count;
559 }
560 fdput_pos(f);
561 return error;
562}
563#endif