blob: d6c82421902aca49f69b6499cb1041118991244a [file] [log] [blame]
Greg Kroah-Hartmanb2441312017-11-01 15:07:57 +01001// SPDX-License-Identifier: GPL-2.0
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
3 * linux/fs/readdir.c
4 *
5 * Copyright (C) 1995 Linus Torvalds
6 */
7
Kevin Winchester85c9fe82010-08-09 17:20:22 -07008#include <linux/stddef.h>
Milind Arun Choudhary022a1692007-05-08 00:29:02 -07009#include <linux/kernel.h>
Paul Gortmaker630d9c42011-11-16 23:57:37 -050010#include <linux/export.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070011#include <linux/time.h>
12#include <linux/mm.h>
13#include <linux/errno.h>
14#include <linux/stat.h>
15#include <linux/file.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070016#include <linux/fs.h>
Heinrich Schuchardtd4c7cf62014-06-04 16:05:41 -070017#include <linux/fsnotify.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#include <linux/dirent.h>
19#include <linux/security.h>
20#include <linux/syscalls.h>
21#include <linux/unistd.h>
Al Viro0460b2a2017-04-08 18:10:08 -040022#include <linux/compat.h>
Linus Torvalds7c0f6ba2016-12-24 11:46:01 -080023#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070024
Linus Torvalds9f79b782016-05-21 21:59:07 -070025/*
Linus Torvalds3e327152023-08-05 12:25:01 -070026 * Some filesystems were never converted to '->iterate_shared()'
27 * and their directory iterators want the inode lock held for
28 * writing. This wrapper allows for converting from the shared
29 * semantics to the exclusive inode use.
30 */
31int wrap_directory_iterator(struct file *file,
32 struct dir_context *ctx,
33 int (*iter)(struct file *, struct dir_context *))
34{
35 struct inode *inode = file_inode(file);
36 int ret;
37
38 /*
39 * We'd love to have an 'inode_upgrade_trylock()' operation,
40 * see the comment in mmap_upgrade_trylock() in mm/memory.c.
41 *
42 * But considering this is for "filesystems that never got
43 * converted", it really doesn't matter.
44 *
45 * Also note that since we have to return with the lock held
46 * for reading, we can't use the "killable()" locking here,
47 * since we do need to get the lock even if we're dying.
48 *
49 * We could do the write part killably and then get the read
50 * lock unconditionally if it mattered, but see above on why
51 * this does the very simplistic conversion.
52 */
53 up_read(&inode->i_rwsem);
54 down_write(&inode->i_rwsem);
55
56 /*
57 * Since we dropped the inode lock, we should do the
58 * DEADDIR test again. See 'iterate_dir()' below.
59 *
60 * Note that we don't need to re-do the f_pos games,
61 * since the file must be locked wrt f_pos anyway.
62 */
63 ret = -ENOENT;
64 if (!IS_DEADDIR(inode))
65 ret = iter(file, ctx);
66
67 downgrade_write(&inode->i_rwsem);
68 return ret;
69}
70EXPORT_SYMBOL(wrap_directory_iterator);
71
72/*
Thorsten Blum992f03f2024-06-02 02:47:30 +020073 * Note the "unsafe_put_user()" semantics: we goto a
Linus Torvalds9f79b782016-05-21 21:59:07 -070074 * label for errors.
Linus Torvalds9f79b782016-05-21 21:59:07 -070075 */
76#define unsafe_copy_dirent_name(_dst, _src, _len, label) do { \
77 char __user *dst = (_dst); \
78 const char *src = (_src); \
79 size_t len = (_len); \
Linus Torvaldsc512c692019-10-07 12:56:48 -070080 unsafe_put_user(0, dst+len, label); \
81 unsafe_copy_to_user(dst, src, len, label); \
Linus Torvalds9f79b782016-05-21 21:59:07 -070082} while (0)
83
84
Al Viro5c0ba4e2013-05-15 13:52:59 -040085int iterate_dir(struct file *file, struct dir_context *ctx)
Linus Torvalds1da177e2005-04-16 15:20:36 -070086{
Al Viro496ad9a2013-01-23 17:07:38 -050087 struct inode *inode = file_inode(file);
Linus Torvalds1da177e2005-04-16 15:20:36 -070088 int res = -ENOTDIR;
Linus Torvalds3e327152023-08-05 12:25:01 -070089
90 if (!file->f_op->iterate_shared)
Linus Torvalds1da177e2005-04-16 15:20:36 -070091 goto out;
92
93 res = security_file_permission(file, MAY_READ);
94 if (res)
95 goto out;
96
Amir Goldsteind9e5d312023-12-12 11:44:40 +020097 res = fsnotify_file_perm(file, MAY_READ);
98 if (res)
99 goto out;
100
Linus Torvalds3e327152023-08-05 12:25:01 -0700101 res = down_read_killable(&inode->i_rwsem);
Kirill Tkhai0dc208b2017-09-29 19:06:48 +0300102 if (res)
103 goto out;
Liam R. Howlettda784512007-12-06 17:39:54 -0500104
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105 res = -ENOENT;
106 if (!IS_DEADDIR(inode)) {
Al Viro2233f312013-05-22 21:44:23 -0400107 ctx->pos = file->f_pos;
Linus Torvalds3e327152023-08-05 12:25:01 -0700108 res = file->f_op->iterate_shared(file, ctx);
Al Viro2233f312013-05-22 21:44:23 -0400109 file->f_pos = ctx->pos;
Heinrich Schuchardtd4c7cf62014-06-04 16:05:41 -0700110 fsnotify_access(file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 file_accessed(file);
112 }
Linus Torvalds3e327152023-08-05 12:25:01 -0700113 inode_unlock_shared(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114out:
115 return res;
116}
Al Viro5c0ba4e2013-05-15 13:52:59 -0400117EXPORT_SYMBOL(iterate_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118
119/*
Linus Torvalds8a23eb82019-10-05 11:32:52 -0700120 * POSIX says that a dirent name cannot contain NULL or a '/'.
121 *
122 * It's not 100% clear what we should really do in this case.
123 * The filesystem is clearly corrupted, but returning a hard
124 * error means that you now don't see any of the other names
125 * either, so that isn't a perfect alternative.
126 *
127 * And if you return an error, what error do you use? Several
128 * filesystems seem to have decided on EUCLEAN being the error
129 * code for EFSCORRUPTED, and that may be the error to use. Or
130 * just EIO, which is perhaps more obvious to users.
131 *
132 * In order to see the other file names in the directory, the
133 * caller might want to make this a "soft" error: skip the
134 * entry, and return the error at the end instead.
135 *
136 * Note that this should likely do a "memchr(name, 0, len)"
137 * check too, since that would be filesystem corruption as
138 * well. However, that case can't actually confuse user space,
139 * which has to do a strlen() on the name anyway to find the
140 * filename length, and the above "soft error" worry means
141 * that it's probably better left alone until we have that
142 * issue clarified.
Linus Torvalds2c6b7bc2020-01-23 10:05:05 -0800143 *
144 * Note the PATH_MAX check - it's arbitrary but the real
145 * kernel limit on a possible path component, not NAME_MAX,
146 * which is the technical standard limit.
Linus Torvalds8a23eb82019-10-05 11:32:52 -0700147 */
148static int verify_dirent_name(const char *name, int len)
149{
Linus Torvalds2c6b7bc2020-01-23 10:05:05 -0800150 if (len <= 0 || len >= PATH_MAX)
Linus Torvalds8a23eb82019-10-05 11:32:52 -0700151 return -EIO;
Linus Torvaldsb9959c72019-10-18 18:41:16 -0400152 if (memchr(name, '/', len))
Linus Torvalds8a23eb82019-10-05 11:32:52 -0700153 return -EIO;
154 return 0;
155}
156
157/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 * Traditional linux readdir() handling..
159 *
160 * "count=1" is a special case, meaning that the buffer is one
161 * dirent-structure in size and that the code can't handle more
162 * anyway. Thus the special "fillonedir()" function for that
163 * case (the low-level handlers don't need to care about this).
164 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165
166#ifdef __ARCH_WANT_OLD_READDIR
167
168struct old_linux_dirent {
169 unsigned long d_ino;
170 unsigned long d_offset;
171 unsigned short d_namlen;
Gustavo A. R. Silva25071352023-06-20 11:30:36 -0600172 char d_name[];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173};
174
175struct readdir_callback {
Al Viro5c0ba4e2013-05-15 13:52:59 -0400176 struct dir_context ctx;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 struct old_linux_dirent __user * dirent;
178 int result;
179};
180
Al Viro25885a32022-08-16 11:57:56 -0400181static bool fillonedir(struct dir_context *ctx, const char *name, int namlen,
Miklos Szerediac7576f2014-10-30 17:37:34 +0100182 loff_t offset, u64 ino, unsigned int d_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183{
Miklos Szerediac7576f2014-10-30 17:37:34 +0100184 struct readdir_callback *buf =
185 container_of(ctx, struct readdir_callback, ctx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186 struct old_linux_dirent __user * dirent;
David Howellsafefdbb2006-10-03 01:13:46 -0700187 unsigned long d_ino;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188
189 if (buf->result)
Al Viro25885a32022-08-16 11:57:56 -0400190 return false;
Linus Torvalds0c93ac62021-04-17 09:27:04 -0700191 buf->result = verify_dirent_name(name, namlen);
Al Viro25885a32022-08-16 11:57:56 -0400192 if (buf->result)
193 return false;
David Howellsafefdbb2006-10-03 01:13:46 -0700194 d_ino = ino;
Al Viro8f3f6552008-08-12 00:28:24 -0400195 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
196 buf->result = -EOVERFLOW;
Al Viro25885a32022-08-16 11:57:56 -0400197 return false;
Al Viro8f3f6552008-08-12 00:28:24 -0400198 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 buf->result++;
200 dirent = buf->dirent;
Al Viro391b7462020-02-18 14:39:56 -0500201 if (!user_write_access_begin(dirent,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 (unsigned long)(dirent->d_name + namlen + 1) -
203 (unsigned long)dirent))
204 goto efault;
Al Viro391b7462020-02-18 14:39:56 -0500205 unsafe_put_user(d_ino, &dirent->d_ino, efault_end);
206 unsafe_put_user(offset, &dirent->d_offset, efault_end);
207 unsafe_put_user(namlen, &dirent->d_namlen, efault_end);
208 unsafe_copy_dirent_name(dirent->d_name, name, namlen, efault_end);
209 user_write_access_end();
Al Viro25885a32022-08-16 11:57:56 -0400210 return true;
Al Viro391b7462020-02-18 14:39:56 -0500211efault_end:
212 user_write_access_end();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213efault:
214 buf->result = -EFAULT;
Al Viro25885a32022-08-16 11:57:56 -0400215 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216}
217
Heiko Carstensd4e82042009-01-14 14:14:34 +0100218SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
219 struct old_linux_dirent __user *, dirent, unsigned int, count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220{
221 int error;
Al Viro63b6df12016-04-20 17:08:21 -0400222 struct fd f = fdget_pos(fd);
Al Viroac6614b2013-05-22 22:22:04 -0400223 struct readdir_callback buf = {
224 .ctx.actor = fillonedir,
225 .dirent = dirent
226 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227
Al Viro2903ff02012-08-28 12:52:22 -0400228 if (!f.file)
Al Viro863ced72012-04-21 18:40:32 -0400229 return -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230
Al Viro5c0ba4e2013-05-15 13:52:59 -0400231 error = iterate_dir(f.file, &buf.ctx);
Al Viro53c9c5c2008-08-24 07:29:52 -0400232 if (buf.result)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233 error = buf.result;
234
Al Viro63b6df12016-04-20 17:08:21 -0400235 fdput_pos(f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 return error;
237}
238
239#endif /* __ARCH_WANT_OLD_READDIR */
240
241/*
242 * New, all-improved, singing, dancing, iBCS2-compliant getdents()
243 * interface.
244 */
245struct linux_dirent {
246 unsigned long d_ino;
247 unsigned long d_off;
248 unsigned short d_reclen;
Gustavo A. R. Silva25071352023-06-20 11:30:36 -0600249 char d_name[];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250};
251
252struct getdents_callback {
Al Viro5c0ba4e2013-05-15 13:52:59 -0400253 struct dir_context ctx;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 struct linux_dirent __user * current_dir;
Linus Torvalds3c2659b2020-01-22 12:37:25 -0800255 int prev_reclen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 int count;
257 int error;
258};
259
Al Viro25885a32022-08-16 11:57:56 -0400260static bool filldir(struct dir_context *ctx, const char *name, int namlen,
Miklos Szerediac7576f2014-10-30 17:37:34 +0100261 loff_t offset, u64 ino, unsigned int d_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262{
Linus Torvalds3c2659b2020-01-22 12:37:25 -0800263 struct linux_dirent __user *dirent, *prev;
Miklos Szerediac7576f2014-10-30 17:37:34 +0100264 struct getdents_callback *buf =
265 container_of(ctx, struct getdents_callback, ctx);
David Howellsafefdbb2006-10-03 01:13:46 -0700266 unsigned long d_ino;
Kevin Winchester85c9fe82010-08-09 17:20:22 -0700267 int reclen = ALIGN(offsetof(struct linux_dirent, d_name) + namlen + 2,
268 sizeof(long));
Linus Torvalds3c2659b2020-01-22 12:37:25 -0800269 int prev_reclen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270
Linus Torvalds8a23eb82019-10-05 11:32:52 -0700271 buf->error = verify_dirent_name(name, namlen);
272 if (unlikely(buf->error))
Al Viro25885a32022-08-16 11:57:56 -0400273 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 buf->error = -EINVAL; /* only used if we fail.. */
275 if (reclen > buf->count)
Al Viro25885a32022-08-16 11:57:56 -0400276 return false;
David Howellsafefdbb2006-10-03 01:13:46 -0700277 d_ino = ino;
Al Viro8f3f6552008-08-12 00:28:24 -0400278 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
279 buf->error = -EOVERFLOW;
Al Viro25885a32022-08-16 11:57:56 -0400280 return false;
Al Viro8f3f6552008-08-12 00:28:24 -0400281 }
Linus Torvalds3c2659b2020-01-22 12:37:25 -0800282 prev_reclen = buf->prev_reclen;
283 if (prev_reclen && signal_pending(current))
Al Viro25885a32022-08-16 11:57:56 -0400284 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 dirent = buf->current_dir;
Linus Torvalds3c2659b2020-01-22 12:37:25 -0800286 prev = (void __user *) dirent - prev_reclen;
Christophe Leroy41cd7802020-04-03 07:20:51 +0000287 if (!user_write_access_begin(prev, reclen + prev_reclen))
Linus Torvalds3c2659b2020-01-22 12:37:25 -0800288 goto efault;
289
290 /* This might be 'dirent->d_off', but if so it will get overwritten */
291 unsafe_put_user(offset, &prev->d_off, efault_end);
Linus Torvalds9f79b782016-05-21 21:59:07 -0700292 unsafe_put_user(d_ino, &dirent->d_ino, efault_end);
293 unsafe_put_user(reclen, &dirent->d_reclen, efault_end);
294 unsafe_put_user(d_type, (char __user *) dirent + reclen - 1, efault_end);
295 unsafe_copy_dirent_name(dirent->d_name, name, namlen, efault_end);
Christophe Leroy41cd7802020-04-03 07:20:51 +0000296 user_write_access_end();
Linus Torvalds9f79b782016-05-21 21:59:07 -0700297
Linus Torvalds3c2659b2020-01-22 12:37:25 -0800298 buf->current_dir = (void __user *)dirent + reclen;
299 buf->prev_reclen = reclen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 buf->count -= reclen;
Al Viro25885a32022-08-16 11:57:56 -0400301 return true;
Linus Torvalds9f79b782016-05-21 21:59:07 -0700302efault_end:
Christophe Leroy41cd7802020-04-03 07:20:51 +0000303 user_write_access_end();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304efault:
305 buf->error = -EFAULT;
Al Viro25885a32022-08-16 11:57:56 -0400306 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307}
308
Heiko Carstens20f37032009-01-14 14:14:23 +0100309SYSCALL_DEFINE3(getdents, unsigned int, fd,
310 struct linux_dirent __user *, dirent, unsigned int, count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311{
Al Viro2903ff02012-08-28 12:52:22 -0400312 struct fd f;
Al Viroac6614b2013-05-22 22:22:04 -0400313 struct getdents_callback buf = {
314 .ctx.actor = filldir,
315 .count = count,
316 .current_dir = dirent
317 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 int error;
319
Al Viro63b6df12016-04-20 17:08:21 -0400320 f = fdget_pos(fd);
Al Viro2903ff02012-08-28 12:52:22 -0400321 if (!f.file)
Al Viro863ced72012-04-21 18:40:32 -0400322 return -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323
Al Viro5c0ba4e2013-05-15 13:52:59 -0400324 error = iterate_dir(f.file, &buf.ctx);
Al Viro53c9c5c2008-08-24 07:29:52 -0400325 if (error >= 0)
326 error = buf.error;
Linus Torvalds3c2659b2020-01-22 12:37:25 -0800327 if (buf.prev_reclen) {
328 struct linux_dirent __user * lastdirent;
329 lastdirent = (void __user *)buf.current_dir - buf.prev_reclen;
330
Al Virobb6f6192013-05-15 18:49:12 -0400331 if (put_user(buf.ctx.pos, &lastdirent->d_off))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 error = -EFAULT;
333 else
334 error = count - buf.count;
335 }
Al Viro63b6df12016-04-20 17:08:21 -0400336 fdput_pos(f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 return error;
338}
339
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340struct getdents_callback64 {
Al Viro5c0ba4e2013-05-15 13:52:59 -0400341 struct dir_context ctx;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 struct linux_dirent64 __user * current_dir;
Linus Torvalds3c2659b2020-01-22 12:37:25 -0800343 int prev_reclen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 int count;
345 int error;
346};
347
Al Viro25885a32022-08-16 11:57:56 -0400348static bool filldir64(struct dir_context *ctx, const char *name, int namlen,
Miklos Szerediac7576f2014-10-30 17:37:34 +0100349 loff_t offset, u64 ino, unsigned int d_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350{
Linus Torvalds3c2659b2020-01-22 12:37:25 -0800351 struct linux_dirent64 __user *dirent, *prev;
Miklos Szerediac7576f2014-10-30 17:37:34 +0100352 struct getdents_callback64 *buf =
353 container_of(ctx, struct getdents_callback64, ctx);
Kevin Winchester85c9fe82010-08-09 17:20:22 -0700354 int reclen = ALIGN(offsetof(struct linux_dirent64, d_name) + namlen + 1,
355 sizeof(u64));
Linus Torvalds3c2659b2020-01-22 12:37:25 -0800356 int prev_reclen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357
Linus Torvalds8a23eb82019-10-05 11:32:52 -0700358 buf->error = verify_dirent_name(name, namlen);
359 if (unlikely(buf->error))
Al Viro25885a32022-08-16 11:57:56 -0400360 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 buf->error = -EINVAL; /* only used if we fail.. */
362 if (reclen > buf->count)
Al Viro25885a32022-08-16 11:57:56 -0400363 return false;
Linus Torvalds3c2659b2020-01-22 12:37:25 -0800364 prev_reclen = buf->prev_reclen;
365 if (prev_reclen && signal_pending(current))
Al Viro25885a32022-08-16 11:57:56 -0400366 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 dirent = buf->current_dir;
Linus Torvalds3c2659b2020-01-22 12:37:25 -0800368 prev = (void __user *)dirent - prev_reclen;
Christophe Leroy41cd7802020-04-03 07:20:51 +0000369 if (!user_write_access_begin(prev, reclen + prev_reclen))
Linus Torvalds3c2659b2020-01-22 12:37:25 -0800370 goto efault;
371
372 /* This might be 'dirent->d_off', but if so it will get overwritten */
373 unsafe_put_user(offset, &prev->d_off, efault_end);
Linus Torvalds9f79b782016-05-21 21:59:07 -0700374 unsafe_put_user(ino, &dirent->d_ino, efault_end);
375 unsafe_put_user(reclen, &dirent->d_reclen, efault_end);
376 unsafe_put_user(d_type, &dirent->d_type, efault_end);
377 unsafe_copy_dirent_name(dirent->d_name, name, namlen, efault_end);
Christophe Leroy41cd7802020-04-03 07:20:51 +0000378 user_write_access_end();
Linus Torvalds9f79b782016-05-21 21:59:07 -0700379
Linus Torvalds3c2659b2020-01-22 12:37:25 -0800380 buf->prev_reclen = reclen;
381 buf->current_dir = (void __user *)dirent + reclen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 buf->count -= reclen;
Al Viro25885a32022-08-16 11:57:56 -0400383 return true;
Linus Torvalds3c2659b2020-01-22 12:37:25 -0800384
Linus Torvalds9f79b782016-05-21 21:59:07 -0700385efault_end:
Christophe Leroy41cd7802020-04-03 07:20:51 +0000386 user_write_access_end();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387efault:
388 buf->error = -EFAULT;
Al Viro25885a32022-08-16 11:57:56 -0400389 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390}
391
Christoph Hellwigfb2da162020-07-14 09:02:07 +0200392SYSCALL_DEFINE3(getdents64, unsigned int, fd,
393 struct linux_dirent64 __user *, dirent, unsigned int, count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394{
Al Viro2903ff02012-08-28 12:52:22 -0400395 struct fd f;
Al Viroac6614b2013-05-22 22:22:04 -0400396 struct getdents_callback64 buf = {
397 .ctx.actor = filldir64,
398 .count = count,
399 .current_dir = dirent
400 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 int error;
402
Al Viro63b6df12016-04-20 17:08:21 -0400403 f = fdget_pos(fd);
Al Viro2903ff02012-08-28 12:52:22 -0400404 if (!f.file)
Al Viro863ced72012-04-21 18:40:32 -0400405 return -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406
Al Viro5c0ba4e2013-05-15 13:52:59 -0400407 error = iterate_dir(f.file, &buf.ctx);
Al Viro53c9c5c2008-08-24 07:29:52 -0400408 if (error >= 0)
409 error = buf.error;
Linus Torvalds3c2659b2020-01-22 12:37:25 -0800410 if (buf.prev_reclen) {
411 struct linux_dirent64 __user * lastdirent;
Al Virobb6f6192013-05-15 18:49:12 -0400412 typeof(lastdirent->d_off) d_off = buf.ctx.pos;
Linus Torvalds3c2659b2020-01-22 12:37:25 -0800413
414 lastdirent = (void __user *) buf.current_dir - buf.prev_reclen;
Al Viro5fb15142020-02-18 22:34:07 -0500415 if (put_user(d_off, &lastdirent->d_off))
Al Viro53c9c5c2008-08-24 07:29:52 -0400416 error = -EFAULT;
417 else
418 error = count - buf.count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 }
Al Viro63b6df12016-04-20 17:08:21 -0400420 fdput_pos(f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 return error;
422}
Al Viro0460b2a2017-04-08 18:10:08 -0400423
424#ifdef CONFIG_COMPAT
425struct compat_old_linux_dirent {
426 compat_ulong_t d_ino;
427 compat_ulong_t d_offset;
428 unsigned short d_namlen;
Gustavo A. R. Silva25071352023-06-20 11:30:36 -0600429 char d_name[];
Al Viro0460b2a2017-04-08 18:10:08 -0400430};
431
432struct compat_readdir_callback {
433 struct dir_context ctx;
434 struct compat_old_linux_dirent __user *dirent;
435 int result;
436};
437
Al Viro25885a32022-08-16 11:57:56 -0400438static bool compat_fillonedir(struct dir_context *ctx, const char *name,
Al Viro0460b2a2017-04-08 18:10:08 -0400439 int namlen, loff_t offset, u64 ino,
440 unsigned int d_type)
441{
442 struct compat_readdir_callback *buf =
443 container_of(ctx, struct compat_readdir_callback, ctx);
444 struct compat_old_linux_dirent __user *dirent;
445 compat_ulong_t d_ino;
446
447 if (buf->result)
Al Viro25885a32022-08-16 11:57:56 -0400448 return false;
Linus Torvalds0c93ac62021-04-17 09:27:04 -0700449 buf->result = verify_dirent_name(name, namlen);
Al Viro25885a32022-08-16 11:57:56 -0400450 if (buf->result)
451 return false;
Al Viro0460b2a2017-04-08 18:10:08 -0400452 d_ino = ino;
453 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
454 buf->result = -EOVERFLOW;
Al Viro25885a32022-08-16 11:57:56 -0400455 return false;
Al Viro0460b2a2017-04-08 18:10:08 -0400456 }
457 buf->result++;
458 dirent = buf->dirent;
Al Viro391b7462020-02-18 14:39:56 -0500459 if (!user_write_access_begin(dirent,
Al Viro0460b2a2017-04-08 18:10:08 -0400460 (unsigned long)(dirent->d_name + namlen + 1) -
461 (unsigned long)dirent))
462 goto efault;
Al Viro391b7462020-02-18 14:39:56 -0500463 unsafe_put_user(d_ino, &dirent->d_ino, efault_end);
464 unsafe_put_user(offset, &dirent->d_offset, efault_end);
465 unsafe_put_user(namlen, &dirent->d_namlen, efault_end);
466 unsafe_copy_dirent_name(dirent->d_name, name, namlen, efault_end);
467 user_write_access_end();
Al Viro25885a32022-08-16 11:57:56 -0400468 return true;
Al Viro391b7462020-02-18 14:39:56 -0500469efault_end:
470 user_write_access_end();
Al Viro0460b2a2017-04-08 18:10:08 -0400471efault:
472 buf->result = -EFAULT;
Al Viro25885a32022-08-16 11:57:56 -0400473 return false;
Al Viro0460b2a2017-04-08 18:10:08 -0400474}
475
476COMPAT_SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
477 struct compat_old_linux_dirent __user *, dirent, unsigned int, count)
478{
479 int error;
480 struct fd f = fdget_pos(fd);
481 struct compat_readdir_callback buf = {
482 .ctx.actor = compat_fillonedir,
483 .dirent = dirent
484 };
485
486 if (!f.file)
487 return -EBADF;
488
489 error = iterate_dir(f.file, &buf.ctx);
490 if (buf.result)
491 error = buf.result;
492
493 fdput_pos(f);
494 return error;
495}
496
497struct compat_linux_dirent {
498 compat_ulong_t d_ino;
499 compat_ulong_t d_off;
500 unsigned short d_reclen;
Gustavo A. R. Silva25071352023-06-20 11:30:36 -0600501 char d_name[];
Al Viro0460b2a2017-04-08 18:10:08 -0400502};
503
504struct compat_getdents_callback {
505 struct dir_context ctx;
506 struct compat_linux_dirent __user *current_dir;
Al Viro82af5992020-02-18 22:33:09 -0500507 int prev_reclen;
Al Viro0460b2a2017-04-08 18:10:08 -0400508 int count;
509 int error;
510};
511
Al Viro25885a32022-08-16 11:57:56 -0400512static bool compat_filldir(struct dir_context *ctx, const char *name, int namlen,
Al Viro0460b2a2017-04-08 18:10:08 -0400513 loff_t offset, u64 ino, unsigned int d_type)
514{
Al Viro82af5992020-02-18 22:33:09 -0500515 struct compat_linux_dirent __user *dirent, *prev;
Al Viro0460b2a2017-04-08 18:10:08 -0400516 struct compat_getdents_callback *buf =
517 container_of(ctx, struct compat_getdents_callback, ctx);
518 compat_ulong_t d_ino;
519 int reclen = ALIGN(offsetof(struct compat_linux_dirent, d_name) +
520 namlen + 2, sizeof(compat_long_t));
Al Viro82af5992020-02-18 22:33:09 -0500521 int prev_reclen;
Al Viro0460b2a2017-04-08 18:10:08 -0400522
Al Viro82af5992020-02-18 22:33:09 -0500523 buf->error = verify_dirent_name(name, namlen);
524 if (unlikely(buf->error))
Al Viro25885a32022-08-16 11:57:56 -0400525 return false;
Al Viro0460b2a2017-04-08 18:10:08 -0400526 buf->error = -EINVAL; /* only used if we fail.. */
527 if (reclen > buf->count)
Al Viro25885a32022-08-16 11:57:56 -0400528 return false;
Al Viro0460b2a2017-04-08 18:10:08 -0400529 d_ino = ino;
530 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
531 buf->error = -EOVERFLOW;
Al Viro25885a32022-08-16 11:57:56 -0400532 return false;
Al Viro0460b2a2017-04-08 18:10:08 -0400533 }
Al Viro82af5992020-02-18 22:33:09 -0500534 prev_reclen = buf->prev_reclen;
535 if (prev_reclen && signal_pending(current))
Al Viro25885a32022-08-16 11:57:56 -0400536 return false;
Al Viro0460b2a2017-04-08 18:10:08 -0400537 dirent = buf->current_dir;
Al Viro82af5992020-02-18 22:33:09 -0500538 prev = (void __user *) dirent - prev_reclen;
539 if (!user_write_access_begin(prev, reclen + prev_reclen))
Al Viro0460b2a2017-04-08 18:10:08 -0400540 goto efault;
Al Viro82af5992020-02-18 22:33:09 -0500541
542 unsafe_put_user(offset, &prev->d_off, efault_end);
543 unsafe_put_user(d_ino, &dirent->d_ino, efault_end);
544 unsafe_put_user(reclen, &dirent->d_reclen, efault_end);
545 unsafe_put_user(d_type, (char __user *) dirent + reclen - 1, efault_end);
546 unsafe_copy_dirent_name(dirent->d_name, name, namlen, efault_end);
547 user_write_access_end();
548
549 buf->prev_reclen = reclen;
550 buf->current_dir = (void __user *)dirent + reclen;
Al Viro0460b2a2017-04-08 18:10:08 -0400551 buf->count -= reclen;
Al Viro25885a32022-08-16 11:57:56 -0400552 return true;
Al Viro82af5992020-02-18 22:33:09 -0500553efault_end:
554 user_write_access_end();
Al Viro0460b2a2017-04-08 18:10:08 -0400555efault:
556 buf->error = -EFAULT;
Al Viro25885a32022-08-16 11:57:56 -0400557 return false;
Al Viro0460b2a2017-04-08 18:10:08 -0400558}
559
560COMPAT_SYSCALL_DEFINE3(getdents, unsigned int, fd,
561 struct compat_linux_dirent __user *, dirent, unsigned int, count)
562{
563 struct fd f;
Al Viro0460b2a2017-04-08 18:10:08 -0400564 struct compat_getdents_callback buf = {
565 .ctx.actor = compat_filldir,
566 .current_dir = dirent,
567 .count = count
568 };
569 int error;
570
Al Viro0460b2a2017-04-08 18:10:08 -0400571 f = fdget_pos(fd);
572 if (!f.file)
573 return -EBADF;
574
575 error = iterate_dir(f.file, &buf.ctx);
576 if (error >= 0)
577 error = buf.error;
Al Viro82af5992020-02-18 22:33:09 -0500578 if (buf.prev_reclen) {
579 struct compat_linux_dirent __user * lastdirent;
580 lastdirent = (void __user *)buf.current_dir - buf.prev_reclen;
581
Al Viro0460b2a2017-04-08 18:10:08 -0400582 if (put_user(buf.ctx.pos, &lastdirent->d_off))
583 error = -EFAULT;
584 else
585 error = count - buf.count;
586 }
587 fdput_pos(f);
588 return error;
589}
590#endif