brintos

brintos / linux-shallow public Read only

0
0
Text · 9.4 KiB · c3a107f Raw
427 lines · c
1// SPDX-License-Identifier: GPL-2.02#include <linux/sched/signal.h>3#include <linux/errno.h>4#include <linux/dcache.h>5#include <linux/path.h>6#include <linux/fdtable.h>7#include <linux/namei.h>8#include <linux/pid.h>9#include <linux/ptrace.h>10#include <linux/bitmap.h>11#include <linux/security.h>12#include <linux/file.h>13#include <linux/seq_file.h>14#include <linux/fs.h>15#include <linux/filelock.h>16 17#include <linux/proc_fs.h>18 19#include "../mount.h"20#include "internal.h"21#include "fd.h"22 23static int seq_show(struct seq_file *m, void *v)24{25	struct files_struct *files = NULL;26	int f_flags = 0, ret = -ENOENT;27	struct file *file = NULL;28	struct task_struct *task;29 30	task = get_proc_task(m->private);31	if (!task)32		return -ENOENT;33 34	task_lock(task);35	files = task->files;36	if (files) {37		unsigned int fd = proc_fd(m->private);38 39		spin_lock(&files->file_lock);40		file = files_lookup_fd_locked(files, fd);41		if (file) {42			f_flags = file->f_flags;43			if (close_on_exec(fd, files))44				f_flags |= O_CLOEXEC;45 46			get_file(file);47			ret = 0;48		}49		spin_unlock(&files->file_lock);50	}51	task_unlock(task);52	put_task_struct(task);53 54	if (ret)55		return ret;56 57	seq_printf(m, "pos:\t%lli\nflags:\t0%o\nmnt_id:\t%i\nino:\t%lu\n",58		   (long long)file->f_pos, f_flags,59		   real_mount(file->f_path.mnt)->mnt_id,60		   file_inode(file)->i_ino);61 62	/* show_fd_locks() never dereferences files, so a stale value is safe */63	show_fd_locks(m, file, files);64	if (seq_has_overflowed(m))65		goto out;66 67	if (file->f_op->show_fdinfo)68		file->f_op->show_fdinfo(m, file);69 70out:71	fput(file);72	return 0;73}74 75static int seq_fdinfo_open(struct inode *inode, struct file *file)76{77	return single_open(file, seq_show, inode);78}79 80/*81 * Shared /proc/pid/fdinfo and /proc/pid/fdinfo/fd permission helper to ensure82 * that the current task has PTRACE_MODE_READ in addition to the normal83 * POSIX-like checks.84 */85static HWJS_SUSPENDS int proc_fdinfo_permission(struct mnt_idmap *idmap, struct inode *inode,86				  int mask)87{88	bool allowed = false;89	struct task_struct *task = get_proc_task(inode);90 91	if (!task)92		return -ESRCH;93 94	allowed = ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS);95	put_task_struct(task);96 97	if (!allowed)98		return -EACCES;99 100	return generic_permission(idmap, inode, mask);101}102 103static const struct inode_operations proc_fdinfo_file_inode_operations = {104	.permission	= proc_fdinfo_permission,105	.setattr	= proc_setattr,106};107 108static const struct file_operations proc_fdinfo_file_operations = {109	.open		= seq_fdinfo_open,110	.read		= seq_read,111	.llseek		= seq_lseek,112	.release	= single_release,113};114 115static bool tid_fd_mode(struct task_struct *task, unsigned fd, fmode_t *mode)116{117	struct file *file;118 119	rcu_read_lock();120	file = task_lookup_fdget_rcu(task, fd);121	rcu_read_unlock();122	if (file) {123		*mode = file->f_mode;124		fput(file);125	}126	return !!file;127}128 129static void tid_fd_update_inode(struct task_struct *task, struct inode *inode,130				fmode_t f_mode)131{132	task_dump_owner(task, 0, &inode->i_uid, &inode->i_gid);133 134	if (S_ISLNK(inode->i_mode)) {135		unsigned i_mode = S_IFLNK;136		if (f_mode & FMODE_READ)137			i_mode |= S_IRUSR | S_IXUSR;138		if (f_mode & FMODE_WRITE)139			i_mode |= S_IWUSR | S_IXUSR;140		inode->i_mode = i_mode;141	}142	security_task_to_inode(task, inode);143}144 145static HWJS_SUSPENDS int tid_fd_revalidate(struct dentry *dentry, unsigned int flags)146{147	struct task_struct *task;148	struct inode *inode;149	unsigned int fd;150 151	if (flags & LOOKUP_RCU)152		return -ECHILD;153 154	inode = d_inode(dentry);155	task = get_proc_task(inode);156	fd = proc_fd(inode);157 158	if (task) {159		fmode_t f_mode;160		if (tid_fd_mode(task, fd, &f_mode)) {161			tid_fd_update_inode(task, inode, f_mode);162			put_task_struct(task);163			return 1;164		}165		put_task_struct(task);166	}167	return 0;168}169 170static const struct dentry_operations tid_fd_dentry_operations = {171	.d_revalidate	= tid_fd_revalidate,172	.d_delete	= pid_delete_dentry,173};174 175static HWJS_SUSPENDS int proc_fd_link(struct dentry *dentry, struct path *path)176{177	struct task_struct *task;178	int ret = -ENOENT;179 180	task = get_proc_task(d_inode(dentry));181	if (task) {182		unsigned int fd = proc_fd(d_inode(dentry));183		struct file *fd_file;184 185		fd_file = fget_task(task, fd);186		if (fd_file) {187			*path = fd_file->f_path;188			path_get(&fd_file->f_path);189			ret = 0;190			fput(fd_file);191		}192		put_task_struct(task);193	}194 195	return ret;196}197 198struct fd_data {199	fmode_t mode;200	unsigned fd;201};202 203static HWJS_SUSPENDS struct dentry *proc_fd_instantiate(struct dentry *dentry,204	struct task_struct *task, const void *ptr)205{206	const struct fd_data *data = ptr;207	struct proc_inode *ei;208	struct inode *inode;209 210	inode = proc_pid_make_inode(dentry->d_sb, task, S_IFLNK);211	if (!inode)212		return ERR_PTR(-ENOENT);213 214	ei = PROC_I(inode);215	ei->fd = data->fd;216 217	inode->i_op = &proc_pid_link_inode_operations;218	inode->i_size = 64;219 220	ei->op.proc_get_link = proc_fd_link;221	tid_fd_update_inode(task, inode, data->mode);222 223	return proc_splice_unmountable(inode, dentry,224				       &tid_fd_dentry_operations);225}226 227static HWJS_SUSPENDS struct dentry *proc_lookupfd_common(struct inode *dir,228					   struct dentry *dentry,229					   instantiate_t instantiate)230{231	struct task_struct *task = get_proc_task(dir);232	struct fd_data data = {.fd = name_to_int(&dentry->d_name)};233	struct dentry *result = ERR_PTR(-ENOENT);234 235	if (!task)236		goto out_no_task;237	if (data.fd == ~0U)238		goto out;239	if (!tid_fd_mode(task, data.fd, &data.mode))240		goto out;241 242	result = instantiate(dentry, task, &data);243out:244	put_task_struct(task);245out_no_task:246	return result;247}248 249static HWJS_SUSPENDS int proc_readfd_common(struct file *file, struct dir_context *ctx,250			      instantiate_t instantiate)251{252	struct task_struct *p = get_proc_task(file_inode(file));253	unsigned int fd;254 255	if (!p)256		return -ENOENT;257 258	if (!dir_emit_dots(file, ctx))259		goto out;260 261	rcu_read_lock();262	for (fd = ctx->pos - 2;; fd++) {263		struct file *f;264		struct fd_data data;265		char name[10 + 1];266		unsigned int len;267 268		f = task_lookup_next_fdget_rcu(p, &fd);269		ctx->pos = fd + 2LL;270		if (!f)271			break;272		data.mode = f->f_mode;273		rcu_read_unlock();274		fput(f);275		data.fd = fd;276 277		len = snprintf(name, sizeof(name), "%u", fd);278		if (!proc_fill_cache(file, ctx,279				     name, len, instantiate, p,280				     &data))281			goto out;282		cond_resched();283		rcu_read_lock();284	}285	rcu_read_unlock();286out:287	put_task_struct(p);288	return 0;289}290 291static HWJS_SUSPENDS int proc_readfd_count(struct inode *inode, loff_t *count)292{293	struct task_struct *p = get_proc_task(inode);294	struct fdtable *fdt;295 296	if (!p)297		return -ENOENT;298 299	task_lock(p);300	if (p->files) {301		rcu_read_lock();302 303		fdt = files_fdtable(p->files);304		*count = bitmap_weight(fdt->open_fds, fdt->max_fds);305 306		rcu_read_unlock();307	}308	task_unlock(p);309 310	put_task_struct(p);311 312	return 0;313}314 315static HWJS_SUSPENDS int proc_fd_iterate(struct file *file, struct dir_context *ctx)316{317	return proc_readfd_common(file, ctx, proc_fd_instantiate);318}319 320const struct file_operations proc_fd_operations = {321	.read		= generic_read_dir,322	.iterate_shared	= proc_fd_iterate,323	.llseek		= generic_file_llseek,324};325 326static HWJS_SUSPENDS struct dentry *proc_lookupfd(struct inode *dir, struct dentry *dentry,327				    unsigned int flags)328{329	return proc_lookupfd_common(dir, dentry, proc_fd_instantiate);330}331 332/*333 * /proc/pid/fd needs a special permission handler so that a process can still334 * access /proc/self/fd after it has executed a setuid().335 */336int proc_fd_permission(struct mnt_idmap *idmap,337		       struct inode *inode, int mask)338{339	struct task_struct *p;340	int rv;341 342	rv = generic_permission(&nop_mnt_idmap, inode, mask);343	if (rv == 0)344		return rv;345 346	rcu_read_lock();347	p = pid_task(proc_pid(inode), PIDTYPE_PID);348	if (p && same_thread_group(p, current))349		rv = 0;350	rcu_read_unlock();351 352	return rv;353}354 355static HWJS_SUSPENDS int proc_fd_getattr(struct mnt_idmap *idmap,356			const struct path *path, struct kstat *stat,357			u32 request_mask, unsigned int query_flags)358{359	struct inode *inode = d_inode(path->dentry);360	int rv = 0;361 362	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);363 364	/* If it's a directory, put the number of open fds there */365	if (S_ISDIR(inode->i_mode)) {366		rv = proc_readfd_count(inode, &stat->size);367		if (rv < 0)368			return rv;369	}370 371	return rv;372}373 374const struct inode_operations proc_fd_inode_operations = {375	.lookup		= proc_lookupfd,376	.permission	= proc_fd_permission,377	.getattr	= proc_fd_getattr,378	.setattr	= proc_setattr,379};380 381static HWJS_SUSPENDS struct dentry *proc_fdinfo_instantiate(struct dentry *dentry,382	struct task_struct *task, const void *ptr)383{384	const struct fd_data *data = ptr;385	struct proc_inode *ei;386	struct inode *inode;387 388	inode = proc_pid_make_inode(dentry->d_sb, task, S_IFREG | S_IRUGO);389	if (!inode)390		return ERR_PTR(-ENOENT);391 392	ei = PROC_I(inode);393	ei->fd = data->fd;394 395	inode->i_op = &proc_fdinfo_file_inode_operations;396 397	inode->i_fop = &proc_fdinfo_file_operations;398	tid_fd_update_inode(task, inode, 0);399 400	return proc_splice_unmountable(inode, dentry,401				       &tid_fd_dentry_operations);402}403 404static HWJS_SUSPENDS struct dentry *405proc_lookupfdinfo(struct inode *dir, struct dentry *dentry, unsigned int flags)406{407	return proc_lookupfd_common(dir, dentry, proc_fdinfo_instantiate);408}409 410static HWJS_SUSPENDS int proc_fdinfo_iterate(struct file *file, struct dir_context *ctx)411{412	return proc_readfd_common(file, ctx,413				  proc_fdinfo_instantiate);414}415 416const struct inode_operations proc_fdinfo_inode_operations = {417	.lookup		= proc_lookupfdinfo,418	.permission	= proc_fdinfo_permission,419	.setattr	= proc_setattr,420};421 422const struct file_operations proc_fdinfo_operations = {423	.read		= generic_read_dir,424	.iterate_shared	= proc_fdinfo_iterate,425	.llseek		= generic_file_llseek,426};427