xref: /openbmc/linux/fs/readdir.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  *  linux/fs/readdir.c
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  *  Copyright (C) 1995  Linus Torvalds
61da177e4SLinus Torvalds  */
71da177e4SLinus Torvalds 
885c9fe8fSKevin Winchester #include <linux/stddef.h>
9022a1692SMilind Arun Choudhary #include <linux/kernel.h>
10630d9c47SPaul Gortmaker #include <linux/export.h>
111da177e4SLinus Torvalds #include <linux/time.h>
121da177e4SLinus Torvalds #include <linux/mm.h>
131da177e4SLinus Torvalds #include <linux/errno.h>
141da177e4SLinus Torvalds #include <linux/stat.h>
151da177e4SLinus Torvalds #include <linux/file.h>
161da177e4SLinus Torvalds #include <linux/fs.h>
17d4c7cf6cSHeinrich Schuchardt #include <linux/fsnotify.h>
181da177e4SLinus Torvalds #include <linux/dirent.h>
191da177e4SLinus Torvalds #include <linux/security.h>
201da177e4SLinus Torvalds #include <linux/syscalls.h>
211da177e4SLinus Torvalds #include <linux/unistd.h>
220460b2a2SAl Viro #include <linux/compat.h>
237c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
241da177e4SLinus Torvalds 
259f79b78eSLinus Torvalds #include <asm/unaligned.h>
269f79b78eSLinus Torvalds 
279f79b78eSLinus Torvalds /*
28*3e327154SLinus Torvalds  * Some filesystems were never converted to '->iterate_shared()'
29*3e327154SLinus Torvalds  * and their directory iterators want the inode lock held for
30*3e327154SLinus Torvalds  * writing. This wrapper allows for converting from the shared
31*3e327154SLinus Torvalds  * semantics to the exclusive inode use.
32*3e327154SLinus Torvalds  */
wrap_directory_iterator(struct file * file,struct dir_context * ctx,int (* iter)(struct file *,struct dir_context *))33*3e327154SLinus Torvalds int wrap_directory_iterator(struct file *file,
34*3e327154SLinus Torvalds 			    struct dir_context *ctx,
35*3e327154SLinus Torvalds 			    int (*iter)(struct file *, struct dir_context *))
36*3e327154SLinus Torvalds {
37*3e327154SLinus Torvalds 	struct inode *inode = file_inode(file);
38*3e327154SLinus Torvalds 	int ret;
39*3e327154SLinus Torvalds 
40*3e327154SLinus Torvalds 	/*
41*3e327154SLinus Torvalds 	 * We'd love to have an 'inode_upgrade_trylock()' operation,
42*3e327154SLinus Torvalds 	 * see the comment in mmap_upgrade_trylock() in mm/memory.c.
43*3e327154SLinus Torvalds 	 *
44*3e327154SLinus Torvalds 	 * But considering this is for "filesystems that never got
45*3e327154SLinus Torvalds 	 * converted", it really doesn't matter.
46*3e327154SLinus Torvalds 	 *
47*3e327154SLinus Torvalds 	 * Also note that since we have to return with the lock held
48*3e327154SLinus Torvalds 	 * for reading, we can't use the "killable()" locking here,
49*3e327154SLinus Torvalds 	 * since we do need to get the lock even if we're dying.
50*3e327154SLinus Torvalds 	 *
51*3e327154SLinus Torvalds 	 * We could do the write part killably and then get the read
52*3e327154SLinus Torvalds 	 * lock unconditionally if it mattered, but see above on why
53*3e327154SLinus Torvalds 	 * this does the very simplistic conversion.
54*3e327154SLinus Torvalds 	 */
55*3e327154SLinus Torvalds 	up_read(&inode->i_rwsem);
56*3e327154SLinus Torvalds 	down_write(&inode->i_rwsem);
57*3e327154SLinus Torvalds 
58*3e327154SLinus Torvalds 	/*
59*3e327154SLinus Torvalds 	 * Since we dropped the inode lock, we should do the
60*3e327154SLinus Torvalds 	 * DEADDIR test again. See 'iterate_dir()' below.
61*3e327154SLinus Torvalds 	 *
62*3e327154SLinus Torvalds 	 * Note that we don't need to re-do the f_pos games,
63*3e327154SLinus Torvalds 	 * since the file must be locked wrt f_pos anyway.
64*3e327154SLinus Torvalds 	 */
65*3e327154SLinus Torvalds 	ret = -ENOENT;
66*3e327154SLinus Torvalds 	if (!IS_DEADDIR(inode))
67*3e327154SLinus Torvalds 		ret = iter(file, ctx);
68*3e327154SLinus Torvalds 
69*3e327154SLinus Torvalds 	downgrade_write(&inode->i_rwsem);
70*3e327154SLinus Torvalds 	return ret;
71*3e327154SLinus Torvalds }
72*3e327154SLinus Torvalds EXPORT_SYMBOL(wrap_directory_iterator);
73*3e327154SLinus Torvalds 
74*3e327154SLinus Torvalds /*
759f79b78eSLinus Torvalds  * Note the "unsafe_put_user() semantics: we goto a
769f79b78eSLinus Torvalds  * label for errors.
779f79b78eSLinus Torvalds  */
789f79b78eSLinus Torvalds #define unsafe_copy_dirent_name(_dst, _src, _len, label) do {	\
799f79b78eSLinus Torvalds 	char __user *dst = (_dst);				\
809f79b78eSLinus Torvalds 	const char *src = (_src);				\
819f79b78eSLinus Torvalds 	size_t len = (_len);					\
82c512c691SLinus Torvalds 	unsafe_put_user(0, dst+len, label);			\
83c512c691SLinus Torvalds 	unsafe_copy_to_user(dst, src, len, label);		\
849f79b78eSLinus Torvalds } while (0)
859f79b78eSLinus Torvalds 
869f79b78eSLinus Torvalds 
iterate_dir(struct file * file,struct dir_context * ctx)875c0ba4e0SAl Viro int iterate_dir(struct file *file, struct dir_context *ctx)
881da177e4SLinus Torvalds {
89496ad9aaSAl Viro 	struct inode *inode = file_inode(file);
901da177e4SLinus Torvalds 	int res = -ENOTDIR;
91*3e327154SLinus Torvalds 
92*3e327154SLinus Torvalds 	if (!file->f_op->iterate_shared)
931da177e4SLinus Torvalds 		goto out;
941da177e4SLinus Torvalds 
951da177e4SLinus Torvalds 	res = security_file_permission(file, MAY_READ);
961da177e4SLinus Torvalds 	if (res)
971da177e4SLinus Torvalds 		goto out;
981da177e4SLinus Torvalds 
990dc208b5SKirill Tkhai 	res = down_read_killable(&inode->i_rwsem);
10000235411SAl Viro 	if (res)
10100235411SAl Viro 		goto out;
102da784511SLiam R. Howlett 
1031da177e4SLinus Torvalds 	res = -ENOENT;
1041da177e4SLinus Torvalds 	if (!IS_DEADDIR(inode)) {
105bb6f619bSAl Viro 		ctx->pos = file->f_pos;
10661922694SAl Viro 		res = file->f_op->iterate_shared(file, ctx);
107bb6f619bSAl Viro 		file->f_pos = ctx->pos;
108d4c7cf6cSHeinrich Schuchardt 		fsnotify_access(file);
1091da177e4SLinus Torvalds 		file_accessed(file);
1101da177e4SLinus Torvalds 	}
11161922694SAl Viro 	inode_unlock_shared(inode);
1121da177e4SLinus Torvalds out:
1131da177e4SLinus Torvalds 	return res;
1141da177e4SLinus Torvalds }
1155c0ba4e0SAl Viro EXPORT_SYMBOL(iterate_dir);
1161da177e4SLinus Torvalds 
1171da177e4SLinus Torvalds /*
1188a23eb80SLinus Torvalds  * POSIX says that a dirent name cannot contain NULL or a '/'.
1198a23eb80SLinus Torvalds  *
1208a23eb80SLinus Torvalds  * It's not 100% clear what we should really do in this case.
1218a23eb80SLinus Torvalds  * The filesystem is clearly corrupted, but returning a hard
1228a23eb80SLinus Torvalds  * error means that you now don't see any of the other names
1238a23eb80SLinus Torvalds  * either, so that isn't a perfect alternative.
1248a23eb80SLinus Torvalds  *
1258a23eb80SLinus Torvalds  * And if you return an error, what error do you use? Several
1268a23eb80SLinus Torvalds  * filesystems seem to have decided on EUCLEAN being the error
1278a23eb80SLinus Torvalds  * code for EFSCORRUPTED, and that may be the error to use. Or
1288a23eb80SLinus Torvalds  * just EIO, which is perhaps more obvious to users.
1298a23eb80SLinus Torvalds  *
1308a23eb80SLinus Torvalds  * In order to see the other file names in the directory, the
1318a23eb80SLinus Torvalds  * caller might want to make this a "soft" error: skip the
1328a23eb80SLinus Torvalds  * entry, and return the error at the end instead.
1338a23eb80SLinus Torvalds  *
1348a23eb80SLinus Torvalds  * Note that this should likely do a "memchr(name, 0, len)"
1358a23eb80SLinus Torvalds  * check too, since that would be filesystem corruption as
1368a23eb80SLinus Torvalds  * well. However, that case can't actually confuse user space,
1378a23eb80SLinus Torvalds  * which has to do a strlen() on the name anyway to find the
1388a23eb80SLinus Torvalds  * filename length, and the above "soft error" worry means
1398a23eb80SLinus Torvalds  * that it's probably better left alone until we have that
1408a23eb80SLinus Torvalds  * issue clarified.
1412c6b7bcdSLinus Torvalds  *
1422c6b7bcdSLinus Torvalds  * Note the PATH_MAX check - it's arbitrary but the real
1432c6b7bcdSLinus Torvalds  * kernel limit on a possible path component, not NAME_MAX,
1442c6b7bcdSLinus Torvalds  * which is the technical standard limit.
1458a23eb80SLinus Torvalds  */
verify_dirent_name(const char * name,int len)1468a23eb80SLinus Torvalds static int verify_dirent_name(const char *name, int len)
1478a23eb80SLinus Torvalds {
1482c6b7bcdSLinus Torvalds 	if (len <= 0 || len >= PATH_MAX)
1498a23eb80SLinus Torvalds 		return -EIO;
150b9959c7aSLinus Torvalds 	if (memchr(name, '/', len))
1518a23eb80SLinus Torvalds 		return -EIO;
1528a23eb80SLinus Torvalds 	return 0;
1538a23eb80SLinus Torvalds }
1548a23eb80SLinus Torvalds 
1558a23eb80SLinus Torvalds /*
1561da177e4SLinus Torvalds  * Traditional linux readdir() handling..
1571da177e4SLinus Torvalds  *
1581da177e4SLinus Torvalds  * "count=1" is a special case, meaning that the buffer is one
1591da177e4SLinus Torvalds  * dirent-structure in size and that the code can't handle more
1601da177e4SLinus Torvalds  * anyway. Thus the special "fillonedir()" function for that
1611da177e4SLinus Torvalds  * case (the low-level handlers don't need to care about this).
1621da177e4SLinus Torvalds  */
1631da177e4SLinus Torvalds 
1641da177e4SLinus Torvalds #ifdef __ARCH_WANT_OLD_READDIR
1651da177e4SLinus Torvalds 
1661da177e4SLinus Torvalds struct old_linux_dirent {
1671da177e4SLinus Torvalds 	unsigned long	d_ino;
1681da177e4SLinus Torvalds 	unsigned long	d_offset;
1691da177e4SLinus Torvalds 	unsigned short	d_namlen;
1702507135eSGustavo A. R. Silva 	char		d_name[];
1711da177e4SLinus Torvalds };
1721da177e4SLinus Torvalds 
1731da177e4SLinus Torvalds struct readdir_callback {
1745c0ba4e0SAl Viro 	struct dir_context ctx;
1751da177e4SLinus Torvalds 	struct old_linux_dirent __user * dirent;
1761da177e4SLinus Torvalds 	int result;
1771da177e4SLinus Torvalds };
1781da177e4SLinus Torvalds 
fillonedir(struct dir_context * ctx,const char * name,int namlen,loff_t offset,u64 ino,unsigned int d_type)17925885a35SAl Viro static bool fillonedir(struct dir_context *ctx, const char *name, int namlen,
180ac7576f4SMiklos Szeredi 		      loff_t offset, u64 ino, unsigned int d_type)
1811da177e4SLinus Torvalds {
182ac7576f4SMiklos Szeredi 	struct readdir_callback *buf =
183ac7576f4SMiklos Szeredi 		container_of(ctx, struct readdir_callback, ctx);
1841da177e4SLinus Torvalds 	struct old_linux_dirent __user * dirent;
185afefdbb2SDavid Howells 	unsigned long d_ino;
1861da177e4SLinus Torvalds 
1871da177e4SLinus Torvalds 	if (buf->result)
18825885a35SAl Viro 		return false;
1890c93ac69SLinus Torvalds 	buf->result = verify_dirent_name(name, namlen);
19025885a35SAl Viro 	if (buf->result)
19125885a35SAl Viro 		return false;
192afefdbb2SDavid Howells 	d_ino = ino;
1938f3f655dSAl Viro 	if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
1948f3f655dSAl Viro 		buf->result = -EOVERFLOW;
19525885a35SAl Viro 		return false;
1968f3f655dSAl Viro 	}
1971da177e4SLinus Torvalds 	buf->result++;
1981da177e4SLinus Torvalds 	dirent = buf->dirent;
199391b7461SAl Viro 	if (!user_write_access_begin(dirent,
2001da177e4SLinus Torvalds 			(unsigned long)(dirent->d_name + namlen + 1) -
2011da177e4SLinus Torvalds 				(unsigned long)dirent))
2021da177e4SLinus Torvalds 		goto efault;
203391b7461SAl Viro 	unsafe_put_user(d_ino, &dirent->d_ino, efault_end);
204391b7461SAl Viro 	unsafe_put_user(offset, &dirent->d_offset, efault_end);
205391b7461SAl Viro 	unsafe_put_user(namlen, &dirent->d_namlen, efault_end);
206391b7461SAl Viro 	unsafe_copy_dirent_name(dirent->d_name, name, namlen, efault_end);
207391b7461SAl Viro 	user_write_access_end();
20825885a35SAl Viro 	return true;
209391b7461SAl Viro efault_end:
210391b7461SAl Viro 	user_write_access_end();
2111da177e4SLinus Torvalds efault:
2121da177e4SLinus Torvalds 	buf->result = -EFAULT;
21325885a35SAl Viro 	return false;
2141da177e4SLinus Torvalds }
2151da177e4SLinus Torvalds 
SYSCALL_DEFINE3(old_readdir,unsigned int,fd,struct old_linux_dirent __user *,dirent,unsigned int,count)216d4e82042SHeiko Carstens SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
217d4e82042SHeiko Carstens 		struct old_linux_dirent __user *, dirent, unsigned int, count)
2181da177e4SLinus Torvalds {
2191da177e4SLinus Torvalds 	int error;
22063b6df14SAl Viro 	struct fd f = fdget_pos(fd);
221ac6614b7SAl Viro 	struct readdir_callback buf = {
222ac6614b7SAl Viro 		.ctx.actor = fillonedir,
223ac6614b7SAl Viro 		.dirent = dirent
224ac6614b7SAl Viro 	};
2251da177e4SLinus Torvalds 
2262903ff01SAl Viro 	if (!f.file)
227863ced7fSAl Viro 		return -EBADF;
2281da177e4SLinus Torvalds 
2295c0ba4e0SAl Viro 	error = iterate_dir(f.file, &buf.ctx);
23053c9c5c0SAl Viro 	if (buf.result)
2311da177e4SLinus Torvalds 		error = buf.result;
2321da177e4SLinus Torvalds 
23363b6df14SAl Viro 	fdput_pos(f);
2341da177e4SLinus Torvalds 	return error;
2351da177e4SLinus Torvalds }
2361da177e4SLinus Torvalds 
2371da177e4SLinus Torvalds #endif /* __ARCH_WANT_OLD_READDIR */
2381da177e4SLinus Torvalds 
2391da177e4SLinus Torvalds /*
2401da177e4SLinus Torvalds  * New, all-improved, singing, dancing, iBCS2-compliant getdents()
2411da177e4SLinus Torvalds  * interface.
2421da177e4SLinus Torvalds  */
2431da177e4SLinus Torvalds struct linux_dirent {
2441da177e4SLinus Torvalds 	unsigned long	d_ino;
2451da177e4SLinus Torvalds 	unsigned long	d_off;
2461da177e4SLinus Torvalds 	unsigned short	d_reclen;
2472507135eSGustavo A. R. Silva 	char		d_name[];
2481da177e4SLinus Torvalds };
2491da177e4SLinus Torvalds 
2501da177e4SLinus Torvalds struct getdents_callback {
2515c0ba4e0SAl Viro 	struct dir_context ctx;
2521da177e4SLinus Torvalds 	struct linux_dirent __user * current_dir;
2533c2659bdSLinus Torvalds 	int prev_reclen;
2541da177e4SLinus Torvalds 	int count;
2551da177e4SLinus Torvalds 	int error;
2561da177e4SLinus Torvalds };
2571da177e4SLinus Torvalds 
filldir(struct dir_context * ctx,const char * name,int namlen,loff_t offset,u64 ino,unsigned int d_type)25825885a35SAl Viro static bool filldir(struct dir_context *ctx, const char *name, int namlen,
259ac7576f4SMiklos Szeredi 		   loff_t offset, u64 ino, unsigned int d_type)
2601da177e4SLinus Torvalds {
2613c2659bdSLinus Torvalds 	struct linux_dirent __user *dirent, *prev;
262ac7576f4SMiklos Szeredi 	struct getdents_callback *buf =
263ac7576f4SMiklos Szeredi 		container_of(ctx, struct getdents_callback, ctx);
264afefdbb2SDavid Howells 	unsigned long d_ino;
26585c9fe8fSKevin Winchester 	int reclen = ALIGN(offsetof(struct linux_dirent, d_name) + namlen + 2,
26685c9fe8fSKevin Winchester 		sizeof(long));
2673c2659bdSLinus Torvalds 	int prev_reclen;
2681da177e4SLinus Torvalds 
2698a23eb80SLinus Torvalds 	buf->error = verify_dirent_name(name, namlen);
2708a23eb80SLinus Torvalds 	if (unlikely(buf->error))
27125885a35SAl Viro 		return false;
2721da177e4SLinus Torvalds 	buf->error = -EINVAL;	/* only used if we fail.. */
2731da177e4SLinus Torvalds 	if (reclen > buf->count)
27425885a35SAl Viro 		return false;
275afefdbb2SDavid Howells 	d_ino = ino;
2768f3f655dSAl Viro 	if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
2778f3f655dSAl Viro 		buf->error = -EOVERFLOW;
27825885a35SAl Viro 		return false;
2798f3f655dSAl Viro 	}
2803c2659bdSLinus Torvalds 	prev_reclen = buf->prev_reclen;
2813c2659bdSLinus Torvalds 	if (prev_reclen && signal_pending(current))
28225885a35SAl Viro 		return false;
2831da177e4SLinus Torvalds 	dirent = buf->current_dir;
2843c2659bdSLinus Torvalds 	prev = (void __user *) dirent - prev_reclen;
28541cd7805SChristophe Leroy 	if (!user_write_access_begin(prev, reclen + prev_reclen))
2863c2659bdSLinus Torvalds 		goto efault;
2873c2659bdSLinus Torvalds 
2883c2659bdSLinus Torvalds 	/* This might be 'dirent->d_off', but if so it will get overwritten */
2893c2659bdSLinus Torvalds 	unsafe_put_user(offset, &prev->d_off, efault_end);
2909f79b78eSLinus Torvalds 	unsafe_put_user(d_ino, &dirent->d_ino, efault_end);
2919f79b78eSLinus Torvalds 	unsafe_put_user(reclen, &dirent->d_reclen, efault_end);
2929f79b78eSLinus Torvalds 	unsafe_put_user(d_type, (char __user *) dirent + reclen - 1, efault_end);
2939f79b78eSLinus Torvalds 	unsafe_copy_dirent_name(dirent->d_name, name, namlen, efault_end);
29441cd7805SChristophe Leroy 	user_write_access_end();
2959f79b78eSLinus Torvalds 
2963c2659bdSLinus Torvalds 	buf->current_dir = (void __user *)dirent + reclen;
2973c2659bdSLinus Torvalds 	buf->prev_reclen = reclen;
2981da177e4SLinus Torvalds 	buf->count -= reclen;
29925885a35SAl Viro 	return true;
3009f79b78eSLinus Torvalds efault_end:
30141cd7805SChristophe Leroy 	user_write_access_end();
3021da177e4SLinus Torvalds efault:
3031da177e4SLinus Torvalds 	buf->error = -EFAULT;
30425885a35SAl Viro 	return false;
3051da177e4SLinus Torvalds }
3061da177e4SLinus Torvalds 
SYSCALL_DEFINE3(getdents,unsigned int,fd,struct linux_dirent __user *,dirent,unsigned int,count)30720f37034SHeiko Carstens SYSCALL_DEFINE3(getdents, unsigned int, fd,
30820f37034SHeiko Carstens 		struct linux_dirent __user *, dirent, unsigned int, count)
3091da177e4SLinus Torvalds {
3102903ff01SAl Viro 	struct fd f;
311ac6614b7SAl Viro 	struct getdents_callback buf = {
312ac6614b7SAl Viro 		.ctx.actor = filldir,
313ac6614b7SAl Viro 		.count = count,
314ac6614b7SAl Viro 		.current_dir = dirent
315ac6614b7SAl Viro 	};
3161da177e4SLinus Torvalds 	int error;
3171da177e4SLinus Torvalds 
31863b6df14SAl Viro 	f = fdget_pos(fd);
3192903ff01SAl Viro 	if (!f.file)
320863ced7fSAl Viro 		return -EBADF;
3211da177e4SLinus Torvalds 
3225c0ba4e0SAl Viro 	error = iterate_dir(f.file, &buf.ctx);
32353c9c5c0SAl Viro 	if (error >= 0)
3241da177e4SLinus Torvalds 		error = buf.error;
3253c2659bdSLinus Torvalds 	if (buf.prev_reclen) {
3263c2659bdSLinus Torvalds 		struct linux_dirent __user * lastdirent;
3273c2659bdSLinus Torvalds 		lastdirent = (void __user *)buf.current_dir - buf.prev_reclen;
3283c2659bdSLinus Torvalds 
329bb6f619bSAl Viro 		if (put_user(buf.ctx.pos, &lastdirent->d_off))
3301da177e4SLinus Torvalds 			error = -EFAULT;
3311da177e4SLinus Torvalds 		else
3321da177e4SLinus Torvalds 			error = count - buf.count;
3331da177e4SLinus Torvalds 	}
33463b6df14SAl Viro 	fdput_pos(f);
3351da177e4SLinus Torvalds 	return error;
3361da177e4SLinus Torvalds }
3371da177e4SLinus Torvalds 
3381da177e4SLinus Torvalds struct getdents_callback64 {
3395c0ba4e0SAl Viro 	struct dir_context ctx;
3401da177e4SLinus Torvalds 	struct linux_dirent64 __user * current_dir;
3413c2659bdSLinus Torvalds 	int prev_reclen;
3421da177e4SLinus Torvalds 	int count;
3431da177e4SLinus Torvalds 	int error;
3441da177e4SLinus Torvalds };
3451da177e4SLinus Torvalds 
filldir64(struct dir_context * ctx,const char * name,int namlen,loff_t offset,u64 ino,unsigned int d_type)34625885a35SAl Viro static bool filldir64(struct dir_context *ctx, const char *name, int namlen,
347ac7576f4SMiklos Szeredi 		     loff_t offset, u64 ino, unsigned int d_type)
3481da177e4SLinus Torvalds {
3493c2659bdSLinus Torvalds 	struct linux_dirent64 __user *dirent, *prev;
350ac7576f4SMiklos Szeredi 	struct getdents_callback64 *buf =
351ac7576f4SMiklos Szeredi 		container_of(ctx, struct getdents_callback64, ctx);
35285c9fe8fSKevin Winchester 	int reclen = ALIGN(offsetof(struct linux_dirent64, d_name) + namlen + 1,
35385c9fe8fSKevin Winchester 		sizeof(u64));
3543c2659bdSLinus Torvalds 	int prev_reclen;
3551da177e4SLinus Torvalds 
3568a23eb80SLinus Torvalds 	buf->error = verify_dirent_name(name, namlen);
3578a23eb80SLinus Torvalds 	if (unlikely(buf->error))
35825885a35SAl Viro 		return false;
3591da177e4SLinus Torvalds 	buf->error = -EINVAL;	/* only used if we fail.. */
3601da177e4SLinus Torvalds 	if (reclen > buf->count)
36125885a35SAl Viro 		return false;
3623c2659bdSLinus Torvalds 	prev_reclen = buf->prev_reclen;
3633c2659bdSLinus Torvalds 	if (prev_reclen && signal_pending(current))
36425885a35SAl Viro 		return false;
3651da177e4SLinus Torvalds 	dirent = buf->current_dir;
3663c2659bdSLinus Torvalds 	prev = (void __user *)dirent - prev_reclen;
36741cd7805SChristophe Leroy 	if (!user_write_access_begin(prev, reclen + prev_reclen))
3683c2659bdSLinus Torvalds 		goto efault;
3693c2659bdSLinus Torvalds 
3703c2659bdSLinus Torvalds 	/* This might be 'dirent->d_off', but if so it will get overwritten */
3713c2659bdSLinus Torvalds 	unsafe_put_user(offset, &prev->d_off, efault_end);
3729f79b78eSLinus Torvalds 	unsafe_put_user(ino, &dirent->d_ino, efault_end);
3739f79b78eSLinus Torvalds 	unsafe_put_user(reclen, &dirent->d_reclen, efault_end);
3749f79b78eSLinus Torvalds 	unsafe_put_user(d_type, &dirent->d_type, efault_end);
3759f79b78eSLinus Torvalds 	unsafe_copy_dirent_name(dirent->d_name, name, namlen, efault_end);
37641cd7805SChristophe Leroy 	user_write_access_end();
3779f79b78eSLinus Torvalds 
3783c2659bdSLinus Torvalds 	buf->prev_reclen = reclen;
3793c2659bdSLinus Torvalds 	buf->current_dir = (void __user *)dirent + reclen;
3801da177e4SLinus Torvalds 	buf->count -= reclen;
38125885a35SAl Viro 	return true;
3823c2659bdSLinus Torvalds 
3839f79b78eSLinus Torvalds efault_end:
38441cd7805SChristophe Leroy 	user_write_access_end();
3851da177e4SLinus Torvalds efault:
3861da177e4SLinus Torvalds 	buf->error = -EFAULT;
38725885a35SAl Viro 	return false;
3881da177e4SLinus Torvalds }
3891da177e4SLinus Torvalds 
SYSCALL_DEFINE3(getdents64,unsigned int,fd,struct linux_dirent64 __user *,dirent,unsigned int,count)390fb2da16cSChristoph Hellwig SYSCALL_DEFINE3(getdents64, unsigned int, fd,
391fb2da16cSChristoph Hellwig 		struct linux_dirent64 __user *, dirent, unsigned int, count)
3921da177e4SLinus Torvalds {
3932903ff01SAl Viro 	struct fd f;
394ac6614b7SAl Viro 	struct getdents_callback64 buf = {
395ac6614b7SAl Viro 		.ctx.actor = filldir64,
396ac6614b7SAl Viro 		.count = count,
397ac6614b7SAl Viro 		.current_dir = dirent
398ac6614b7SAl Viro 	};
3991da177e4SLinus Torvalds 	int error;
4001da177e4SLinus Torvalds 
40163b6df14SAl Viro 	f = fdget_pos(fd);
4022903ff01SAl Viro 	if (!f.file)
403863ced7fSAl Viro 		return -EBADF;
4041da177e4SLinus Torvalds 
4055c0ba4e0SAl Viro 	error = iterate_dir(f.file, &buf.ctx);
40653c9c5c0SAl Viro 	if (error >= 0)
4071da177e4SLinus Torvalds 		error = buf.error;
4083c2659bdSLinus Torvalds 	if (buf.prev_reclen) {
4093c2659bdSLinus Torvalds 		struct linux_dirent64 __user * lastdirent;
410bb6f619bSAl Viro 		typeof(lastdirent->d_off) d_off = buf.ctx.pos;
4113c2659bdSLinus Torvalds 
4123c2659bdSLinus Torvalds 		lastdirent = (void __user *) buf.current_dir - buf.prev_reclen;
4135fb15141SAl Viro 		if (put_user(d_off, &lastdirent->d_off))
41453c9c5c0SAl Viro 			error = -EFAULT;
41553c9c5c0SAl Viro 		else
4161da177e4SLinus Torvalds 			error = count - buf.count;
4171da177e4SLinus Torvalds 	}
41863b6df14SAl Viro 	fdput_pos(f);
4191da177e4SLinus Torvalds 	return error;
4201da177e4SLinus Torvalds }
4210460b2a2SAl Viro 
4220460b2a2SAl Viro #ifdef CONFIG_COMPAT
4230460b2a2SAl Viro struct compat_old_linux_dirent {
4240460b2a2SAl Viro 	compat_ulong_t	d_ino;
4250460b2a2SAl Viro 	compat_ulong_t	d_offset;
4260460b2a2SAl Viro 	unsigned short	d_namlen;
4272507135eSGustavo A. R. Silva 	char		d_name[];
4280460b2a2SAl Viro };
4290460b2a2SAl Viro 
4300460b2a2SAl Viro struct compat_readdir_callback {
4310460b2a2SAl Viro 	struct dir_context ctx;
4320460b2a2SAl Viro 	struct compat_old_linux_dirent __user *dirent;
4330460b2a2SAl Viro 	int result;
4340460b2a2SAl Viro };
4350460b2a2SAl Viro 
compat_fillonedir(struct dir_context * ctx,const char * name,int namlen,loff_t offset,u64 ino,unsigned int d_type)43625885a35SAl Viro static bool compat_fillonedir(struct dir_context *ctx, const char *name,
4370460b2a2SAl Viro 			     int namlen, loff_t offset, u64 ino,
4380460b2a2SAl Viro 			     unsigned int d_type)
4390460b2a2SAl Viro {
4400460b2a2SAl Viro 	struct compat_readdir_callback *buf =
4410460b2a2SAl Viro 		container_of(ctx, struct compat_readdir_callback, ctx);
4420460b2a2SAl Viro 	struct compat_old_linux_dirent __user *dirent;
4430460b2a2SAl Viro 	compat_ulong_t d_ino;
4440460b2a2SAl Viro 
4450460b2a2SAl Viro 	if (buf->result)
44625885a35SAl Viro 		return false;
4470c93ac69SLinus Torvalds 	buf->result = verify_dirent_name(name, namlen);
44825885a35SAl Viro 	if (buf->result)
44925885a35SAl Viro 		return false;
4500460b2a2SAl Viro 	d_ino = ino;
4510460b2a2SAl Viro 	if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
4520460b2a2SAl Viro 		buf->result = -EOVERFLOW;
45325885a35SAl Viro 		return false;
4540460b2a2SAl Viro 	}
4550460b2a2SAl Viro 	buf->result++;
4560460b2a2SAl Viro 	dirent = buf->dirent;
457391b7461SAl Viro 	if (!user_write_access_begin(dirent,
4580460b2a2SAl Viro 			(unsigned long)(dirent->d_name + namlen + 1) -
4590460b2a2SAl Viro 				(unsigned long)dirent))
4600460b2a2SAl Viro 		goto efault;
461391b7461SAl Viro 	unsafe_put_user(d_ino, &dirent->d_ino, efault_end);
462391b7461SAl Viro 	unsafe_put_user(offset, &dirent->d_offset, efault_end);
463391b7461SAl Viro 	unsafe_put_user(namlen, &dirent->d_namlen, efault_end);
464391b7461SAl Viro 	unsafe_copy_dirent_name(dirent->d_name, name, namlen, efault_end);
465391b7461SAl Viro 	user_write_access_end();
46625885a35SAl Viro 	return true;
467391b7461SAl Viro efault_end:
468391b7461SAl Viro 	user_write_access_end();
4690460b2a2SAl Viro efault:
4700460b2a2SAl Viro 	buf->result = -EFAULT;
47125885a35SAl Viro 	return false;
4720460b2a2SAl Viro }
4730460b2a2SAl Viro 
COMPAT_SYSCALL_DEFINE3(old_readdir,unsigned int,fd,struct compat_old_linux_dirent __user *,dirent,unsigned int,count)4740460b2a2SAl Viro COMPAT_SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
4750460b2a2SAl Viro 		struct compat_old_linux_dirent __user *, dirent, unsigned int, count)
4760460b2a2SAl Viro {
4770460b2a2SAl Viro 	int error;
4780460b2a2SAl Viro 	struct fd f = fdget_pos(fd);
4790460b2a2SAl Viro 	struct compat_readdir_callback buf = {
4800460b2a2SAl Viro 		.ctx.actor = compat_fillonedir,
4810460b2a2SAl Viro 		.dirent = dirent
4820460b2a2SAl Viro 	};
4830460b2a2SAl Viro 
4840460b2a2SAl Viro 	if (!f.file)
4850460b2a2SAl Viro 		return -EBADF;
4860460b2a2SAl Viro 
4870460b2a2SAl Viro 	error = iterate_dir(f.file, &buf.ctx);
4880460b2a2SAl Viro 	if (buf.result)
4890460b2a2SAl Viro 		error = buf.result;
4900460b2a2SAl Viro 
4910460b2a2SAl Viro 	fdput_pos(f);
4920460b2a2SAl Viro 	return error;
4930460b2a2SAl Viro }
4940460b2a2SAl Viro 
4950460b2a2SAl Viro struct compat_linux_dirent {
4960460b2a2SAl Viro 	compat_ulong_t	d_ino;
4970460b2a2SAl Viro 	compat_ulong_t	d_off;
4980460b2a2SAl Viro 	unsigned short	d_reclen;
4992507135eSGustavo A. R. Silva 	char		d_name[];
5000460b2a2SAl Viro };
5010460b2a2SAl Viro 
5020460b2a2SAl Viro struct compat_getdents_callback {
5030460b2a2SAl Viro 	struct dir_context ctx;
5040460b2a2SAl Viro 	struct compat_linux_dirent __user *current_dir;
50582af599bSAl Viro 	int prev_reclen;
5060460b2a2SAl Viro 	int count;
5070460b2a2SAl Viro 	int error;
5080460b2a2SAl Viro };
5090460b2a2SAl Viro 
compat_filldir(struct dir_context * ctx,const char * name,int namlen,loff_t offset,u64 ino,unsigned int d_type)51025885a35SAl Viro static bool compat_filldir(struct dir_context *ctx, const char *name, int namlen,
5110460b2a2SAl Viro 		loff_t offset, u64 ino, unsigned int d_type)
5120460b2a2SAl Viro {
51382af599bSAl Viro 	struct compat_linux_dirent __user *dirent, *prev;
5140460b2a2SAl Viro 	struct compat_getdents_callback *buf =
5150460b2a2SAl Viro 		container_of(ctx, struct compat_getdents_callback, ctx);
5160460b2a2SAl Viro 	compat_ulong_t d_ino;
5170460b2a2SAl Viro 	int reclen = ALIGN(offsetof(struct compat_linux_dirent, d_name) +
5180460b2a2SAl Viro 		namlen + 2, sizeof(compat_long_t));
51982af599bSAl Viro 	int prev_reclen;
5200460b2a2SAl Viro 
52182af599bSAl Viro 	buf->error = verify_dirent_name(name, namlen);
52282af599bSAl Viro 	if (unlikely(buf->error))
52325885a35SAl Viro 		return false;
5240460b2a2SAl Viro 	buf->error = -EINVAL;	/* only used if we fail.. */
5250460b2a2SAl Viro 	if (reclen > buf->count)
52625885a35SAl Viro 		return false;
5270460b2a2SAl Viro 	d_ino = ino;
5280460b2a2SAl Viro 	if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
5290460b2a2SAl Viro 		buf->error = -EOVERFLOW;
53025885a35SAl Viro 		return false;
5310460b2a2SAl Viro 	}
53282af599bSAl Viro 	prev_reclen = buf->prev_reclen;
53382af599bSAl Viro 	if (prev_reclen && signal_pending(current))
53425885a35SAl Viro 		return false;
5350460b2a2SAl Viro 	dirent = buf->current_dir;
53682af599bSAl Viro 	prev = (void __user *) dirent - prev_reclen;
53782af599bSAl Viro 	if (!user_write_access_begin(prev, reclen + prev_reclen))
5380460b2a2SAl Viro 		goto efault;
53982af599bSAl Viro 
54082af599bSAl Viro 	unsafe_put_user(offset, &prev->d_off, efault_end);
54182af599bSAl Viro 	unsafe_put_user(d_ino, &dirent->d_ino, efault_end);
54282af599bSAl Viro 	unsafe_put_user(reclen, &dirent->d_reclen, efault_end);
54382af599bSAl Viro 	unsafe_put_user(d_type, (char __user *) dirent + reclen - 1, efault_end);
54482af599bSAl Viro 	unsafe_copy_dirent_name(dirent->d_name, name, namlen, efault_end);
54582af599bSAl Viro 	user_write_access_end();
54682af599bSAl Viro 
54782af599bSAl Viro 	buf->prev_reclen = reclen;
54882af599bSAl Viro 	buf->current_dir = (void __user *)dirent + reclen;
5490460b2a2SAl Viro 	buf->count -= reclen;
55025885a35SAl Viro 	return true;
55182af599bSAl Viro efault_end:
55282af599bSAl Viro 	user_write_access_end();
5530460b2a2SAl Viro efault:
5540460b2a2SAl Viro 	buf->error = -EFAULT;
55525885a35SAl Viro 	return false;
5560460b2a2SAl Viro }
5570460b2a2SAl Viro 
COMPAT_SYSCALL_DEFINE3(getdents,unsigned int,fd,struct compat_linux_dirent __user *,dirent,unsigned int,count)5580460b2a2SAl Viro COMPAT_SYSCALL_DEFINE3(getdents, unsigned int, fd,
5590460b2a2SAl Viro 		struct compat_linux_dirent __user *, dirent, unsigned int, count)
5600460b2a2SAl Viro {
5610460b2a2SAl Viro 	struct fd f;
5620460b2a2SAl Viro 	struct compat_getdents_callback buf = {
5630460b2a2SAl Viro 		.ctx.actor = compat_filldir,
5640460b2a2SAl Viro 		.current_dir = dirent,
5650460b2a2SAl Viro 		.count = count
5660460b2a2SAl Viro 	};
5670460b2a2SAl Viro 	int error;
5680460b2a2SAl Viro 
5690460b2a2SAl Viro 	f = fdget_pos(fd);
5700460b2a2SAl Viro 	if (!f.file)
5710460b2a2SAl Viro 		return -EBADF;
5720460b2a2SAl Viro 
5730460b2a2SAl Viro 	error = iterate_dir(f.file, &buf.ctx);
5740460b2a2SAl Viro 	if (error >= 0)
5750460b2a2SAl Viro 		error = buf.error;
57682af599bSAl Viro 	if (buf.prev_reclen) {
57782af599bSAl Viro 		struct compat_linux_dirent __user * lastdirent;
57882af599bSAl Viro 		lastdirent = (void __user *)buf.current_dir - buf.prev_reclen;
57982af599bSAl Viro 
5800460b2a2SAl Viro 		if (put_user(buf.ctx.pos, &lastdirent->d_off))
5810460b2a2SAl Viro 			error = -EFAULT;
5820460b2a2SAl Viro 		else
5830460b2a2SAl Viro 			error = count - buf.count;
5840460b2a2SAl Viro 	}
5850460b2a2SAl Viro 	fdput_pos(f);
5860460b2a2SAl Viro 	return error;
5870460b2a2SAl Viro }
5880460b2a2SAl Viro #endif
589