cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

readdir.c (14221B)


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