brintos

brintos / linux-shallow public Read only

0
0
Text · 11.4 KiB · 5f4da5c Raw
449 lines · c
1/* SPDX-License-Identifier: GPL-2.0 */2#include <linux/syscalls.h>3#include <linux/export.h>4#include <linux/uaccess.h>5#include <linux/fs_struct.h>6#include <linux/fs.h>7#include <linux/slab.h>8#include <linux/prefetch.h>9#include "mount.h"10#include "internal.h"11 12struct prepend_buffer {13	char *buf;14	int len;15};16#define DECLARE_BUFFER(__name, __buf, __len) \17	struct prepend_buffer __name = {.buf = __buf + __len, .len = __len}18 19static char *extract_string(struct prepend_buffer *p)20{21	if (likely(p->len >= 0))22		return p->buf;23	return ERR_PTR(-ENAMETOOLONG);24}25 26static bool prepend_char(struct prepend_buffer *p, unsigned char c)27{28	if (likely(p->len > 0)) {29		p->len--;30		*--p->buf = c;31		return true;32	}33	p->len = -1;34	return false;35}36 37/*38 * The source of the prepend data can be an optimistic load39 * of a dentry name and length. And because we don't hold any40 * locks, the length and the pointer to the name may not be41 * in sync if a concurrent rename happens, and the kernel42 * copy might fault as a result.43 *44 * The end result will correct itself when we check the45 * rename sequence count, but we need to be able to handle46 * the fault gracefully.47 */48static bool prepend_copy(void *dst, const void *src, int len)49{50	if (unlikely(copy_from_kernel_nofault(dst, src, len))) {51		memset(dst, 'x', len);52		return false;53	}54	return true;55}56 57static bool prepend(struct prepend_buffer *p, const char *str, int namelen)58{59	// Already overflowed?60	if (p->len < 0)61		return false;62 63	// Will overflow?64	if (p->len < namelen) {65		// Fill as much as possible from the end of the name66		str += namelen - p->len;67		p->buf -= p->len;68		prepend_copy(p->buf, str, p->len);69		p->len = -1;70		return false;71	}72 73	// Fits fully74	p->len -= namelen;75	p->buf -= namelen;76	return prepend_copy(p->buf, str, namelen);77}78 79/**80 * prepend_name - prepend a pathname in front of current buffer pointer81 * @p: prepend buffer which contains buffer pointer and allocated length82 * @name: name string and length qstr structure83 *84 * With RCU path tracing, it may race with d_move(). Use READ_ONCE() to85 * make sure that either the old or the new name pointer and length are86 * fetched. However, there may be mismatch between length and pointer.87 * But since the length cannot be trusted, we need to copy the name very88 * carefully when doing the prepend_copy(). It also prepends "/" at89 * the beginning of the name. The sequence number check at the caller will90 * retry it again when a d_move() does happen. So any garbage in the buffer91 * due to mismatched pointer and length will be discarded.92 *93 * Load acquire is needed to make sure that we see the new name data even94 * if we might get the length wrong.95 */96static bool prepend_name(struct prepend_buffer *p, const struct qstr *name)97{98	const char *dname = smp_load_acquire(&name->name); /* ^^^ */99	u32 dlen = READ_ONCE(name->len);100 101	return prepend(p, dname, dlen) && prepend_char(p, '/');102}103 104static int __prepend_path(const struct dentry *dentry, const struct mount *mnt,105			  const struct path *root, struct prepend_buffer *p)106{107	while (dentry != root->dentry || &mnt->mnt != root->mnt) {108		const struct dentry *parent = READ_ONCE(dentry->d_parent);109 110		if (dentry == mnt->mnt.mnt_root) {111			struct mount *m = READ_ONCE(mnt->mnt_parent);112			struct mnt_namespace *mnt_ns;113 114			if (likely(mnt != m)) {115				dentry = READ_ONCE(mnt->mnt_mountpoint);116				mnt = m;117				continue;118			}119			/* Global root */120			mnt_ns = READ_ONCE(mnt->mnt_ns);121			/* open-coded is_mounted() to use local mnt_ns */122			if (!IS_ERR_OR_NULL(mnt_ns) && !is_anon_ns(mnt_ns))123				return 1;	// absolute root124			else125				return 2;	// detached or not attached yet126		}127 128		if (unlikely(dentry == parent))129			/* Escaped? */130			return 3;131 132		prefetch(parent);133		if (!prepend_name(p, &dentry->d_name))134			break;135		dentry = parent;136	}137	return 0;138}139 140/**141 * prepend_path - Prepend path string to a buffer142 * @path: the dentry/vfsmount to report143 * @root: root vfsmnt/dentry144 * @p: prepend buffer which contains buffer pointer and allocated length145 *146 * The function will first try to write out the pathname without taking any147 * lock other than the RCU read lock to make sure that dentries won't go away.148 * It only checks the sequence number of the global rename_lock as any change149 * in the dentry's d_seq will be preceded by changes in the rename_lock150 * sequence number. If the sequence number had been changed, it will restart151 * the whole pathname back-tracing sequence again by taking the rename_lock.152 * In this case, there is no need to take the RCU read lock as the recursive153 * parent pointer references will keep the dentry chain alive as long as no154 * rename operation is performed.155 */156static int prepend_path(const struct path *path,157			const struct path *root,158			struct prepend_buffer *p)159{160	unsigned seq, m_seq = 0;161	struct prepend_buffer b;162	int error;163 164	rcu_read_lock();165restart_mnt:166	read_seqbegin_or_lock(&mount_lock, &m_seq);167	seq = 0;168	rcu_read_lock();169restart:170	b = *p;171	read_seqbegin_or_lock(&rename_lock, &seq);172	error = __prepend_path(path->dentry, real_mount(path->mnt), root, &b);173	if (!(seq & 1))174		rcu_read_unlock();175	if (need_seqretry(&rename_lock, seq)) {176		seq = 1;177		goto restart;178	}179	done_seqretry(&rename_lock, seq);180 181	if (!(m_seq & 1))182		rcu_read_unlock();183	if (need_seqretry(&mount_lock, m_seq)) {184		m_seq = 1;185		goto restart_mnt;186	}187	done_seqretry(&mount_lock, m_seq);188 189	if (unlikely(error == 3))190		b = *p;191 192	if (b.len == p->len)193		prepend_char(&b, '/');194 195	*p = b;196	return error;197}198 199/**200 * __d_path - return the path of a dentry201 * @path: the dentry/vfsmount to report202 * @root: root vfsmnt/dentry203 * @buf: buffer to return value in204 * @buflen: buffer length205 *206 * Convert a dentry into an ASCII path name.207 *208 * Returns a pointer into the buffer or an error code if the209 * path was too long.210 *211 * "buflen" should be positive.212 *213 * If the path is not reachable from the supplied root, return %NULL.214 */215char *__d_path(const struct path *path,216	       const struct path *root,217	       char *buf, int buflen)218{219	DECLARE_BUFFER(b, buf, buflen);220 221	prepend_char(&b, 0);222	if (unlikely(prepend_path(path, root, &b) > 0))223		return NULL;224	return extract_string(&b);225}226 227char *d_absolute_path(const struct path *path,228	       char *buf, int buflen)229{230	struct path root = {};231	DECLARE_BUFFER(b, buf, buflen);232 233	prepend_char(&b, 0);234	if (unlikely(prepend_path(path, &root, &b) > 1))235		return ERR_PTR(-EINVAL);236	return extract_string(&b);237}238 239static void get_fs_root_rcu(struct fs_struct *fs, struct path *root)240{241	unsigned seq;242 243	do {244		seq = read_seqcount_begin(&fs->seq);245		*root = fs->root;246	} while (read_seqcount_retry(&fs->seq, seq));247}248 249/**250 * d_path - return the path of a dentry251 * @path: path to report252 * @buf: buffer to return value in253 * @buflen: buffer length254 *255 * Convert a dentry into an ASCII path name. If the entry has been deleted256 * the string " (deleted)" is appended. Note that this is ambiguous.257 *258 * Returns a pointer into the buffer or an error code if the path was259 * too long. Note: Callers should use the returned pointer, not the passed260 * in buffer, to use the name! The implementation often starts at an offset261 * into the buffer, and may leave 0 bytes at the start.262 *263 * "buflen" should be positive.264 */265char *d_path(const struct path *path, char *buf, int buflen)266{267	DECLARE_BUFFER(b, buf, buflen);268	struct path root;269 270	/*271	 * We have various synthetic filesystems that never get mounted.  On272	 * these filesystems dentries are never used for lookup purposes, and273	 * thus don't need to be hashed.  They also don't need a name until a274	 * user wants to identify the object in /proc/pid/fd/.  The little hack275	 * below allows us to generate a name for these objects on demand:276	 *277	 * Some pseudo inodes are mountable.  When they are mounted278	 * path->dentry == path->mnt->mnt_root.  In that case don't call d_dname279	 * and instead have d_path return the mounted path.280	 */281	if (path->dentry->d_op && path->dentry->d_op->d_dname &&282	    (!IS_ROOT(path->dentry) || path->dentry != path->mnt->mnt_root))283		return path->dentry->d_op->d_dname(path->dentry, buf, buflen);284 285	rcu_read_lock();286	get_fs_root_rcu(current->fs, &root);287	if (unlikely(d_unlinked(path->dentry)))288		prepend(&b, " (deleted)", 11);289	else290		prepend_char(&b, 0);291	prepend_path(path, &root, &b);292	rcu_read_unlock();293 294	return extract_string(&b);295}296EXPORT_SYMBOL(d_path);297 298/*299 * Helper function for dentry_operations.d_dname() members300 */301char *dynamic_dname(char *buffer, int buflen, const char *fmt, ...)302{303	va_list args;304	char temp[64];305	int sz;306 307	va_start(args, fmt);308	sz = vsnprintf(temp, sizeof(temp), fmt, args) + 1;309	va_end(args);310 311	if (sz > sizeof(temp) || sz > buflen)312		return ERR_PTR(-ENAMETOOLONG);313 314	buffer += buflen - sz;315	return memcpy(buffer, temp, sz);316}317 318char *simple_dname(struct dentry *dentry, char *buffer, int buflen)319{320	DECLARE_BUFFER(b, buffer, buflen);321	/* these dentries are never renamed, so d_lock is not needed */322	prepend(&b, " (deleted)", 11);323	prepend(&b, dentry->d_name.name, dentry->d_name.len);324	prepend_char(&b, '/');325	return extract_string(&b);326}327 328/*329 * Write full pathname from the root of the filesystem into the buffer.330 */331static char *__dentry_path(const struct dentry *d, struct prepend_buffer *p)332{333	const struct dentry *dentry;334	struct prepend_buffer b;335	int seq = 0;336 337	rcu_read_lock();338restart:339	dentry = d;340	b = *p;341	read_seqbegin_or_lock(&rename_lock, &seq);342	while (!IS_ROOT(dentry)) {343		const struct dentry *parent = dentry->d_parent;344 345		prefetch(parent);346		if (!prepend_name(&b, &dentry->d_name))347			break;348		dentry = parent;349	}350	if (!(seq & 1))351		rcu_read_unlock();352	if (need_seqretry(&rename_lock, seq)) {353		seq = 1;354		goto restart;355	}356	done_seqretry(&rename_lock, seq);357	if (b.len == p->len)358		prepend_char(&b, '/');359	return extract_string(&b);360}361 362char *dentry_path_raw(const struct dentry *dentry, char *buf, int buflen)363{364	DECLARE_BUFFER(b, buf, buflen);365 366	prepend_char(&b, 0);367	return __dentry_path(dentry, &b);368}369EXPORT_SYMBOL(dentry_path_raw);370 371char *dentry_path(const struct dentry *dentry, char *buf, int buflen)372{373	DECLARE_BUFFER(b, buf, buflen);374 375	if (unlikely(d_unlinked(dentry)))376		prepend(&b, "//deleted", 10);377	else378		prepend_char(&b, 0);379	return __dentry_path(dentry, &b);380}381 382static void get_fs_root_and_pwd_rcu(struct fs_struct *fs, struct path *root,383				    struct path *pwd)384{385	unsigned seq;386 387	do {388		seq = read_seqcount_begin(&fs->seq);389		*root = fs->root;390		*pwd = fs->pwd;391	} while (read_seqcount_retry(&fs->seq, seq));392}393 394/*395 * NOTE! The user-level library version returns a396 * character pointer. The kernel system call just397 * returns the length of the buffer filled (which398 * includes the ending '\0' character), or a negative399 * error value. So libc would do something like400 *401 *	char *getcwd(char * buf, size_t size)402 *	{403 *		int retval;404 *405 *		retval = sys_getcwd(buf, size);406 *		if (retval >= 0)407 *			return buf;408 *		errno = -retval;409 *		return NULL;410 *	}411 */412SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size)413{414	int error;415	struct path pwd, root;416	char *page = __getname();417 418	if (!page)419		return -ENOMEM;420 421	rcu_read_lock();422	get_fs_root_and_pwd_rcu(current->fs, &root, &pwd);423 424	if (unlikely(d_unlinked(pwd.dentry))) {425		rcu_read_unlock();426		error = -ENOENT;427	} else {428		unsigned len;429		DECLARE_BUFFER(b, page, PATH_MAX);430 431		prepend_char(&b, 0);432		if (unlikely(prepend_path(&pwd, &root, &b) > 0))433			prepend(&b, "(unreachable)", 13);434		rcu_read_unlock();435 436		len = PATH_MAX - b.len;437		if (unlikely(len > PATH_MAX))438			error = -ENAMETOOLONG;439		else if (unlikely(len > size))440			error = -ERANGE;441		else if (copy_to_user(buf, b.buf, len))442			error = -EFAULT;443		else444			error = len;445	}446	__putname(page);447	return error;448}449