Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c3c073f8 authored by Al Viro's avatar Al Viro
Browse files

new helper: iterate_fd()



iterates through the opened files in given descriptor table,
calling a supplied function; we stop once non-zero is returned.
Callback gets struct file *, descriptor number and const void *
argument passed to iterator.  It is called with files->file_lock
held, so it is not allowed to block.

tty_io, netprio_cgroup and selinux flush_unauthorized_files()
converted to its use.

Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent ad47bd72
Loading
Loading
Loading
Loading
+13 −23
Original line number Diff line number Diff line
@@ -2791,6 +2791,13 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd,
}
#endif

static int this_tty(const void *t, struct file *file, unsigned fd)
{
	if (likely(file->f_op->read != tty_read))
		return 0;
	return file_tty(file) != t ? 0 : fd + 1;
}
	
/*
 * This implements the "Secure Attention Key" ---  the idea is to
 * prevent trojan horses by killing all processes associated with this
@@ -2818,8 +2825,6 @@ void __do_SAK(struct tty_struct *tty)
	struct task_struct *g, *p;
	struct pid *session;
	int		i;
	struct file	*filp;
	struct fdtable *fdt;

	if (!tty)
		return;
@@ -2849,27 +2854,12 @@ void __do_SAK(struct tty_struct *tty)
			continue;
		}
		task_lock(p);
		if (p->files) {
			/*
			 * We don't take a ref to the file, so we must
			 * hold ->file_lock instead.
			 */
			spin_lock(&p->files->file_lock);
			fdt = files_fdtable(p->files);
			for (i = 0; i < fdt->max_fds; i++) {
				filp = fcheck_files(p->files, i);
				if (!filp)
					continue;
				if (filp->f_op->read == tty_read &&
				    file_tty(filp) == tty) {
		i = iterate_fd(p->files, 0, this_tty, tty);
		if (i != 0) {
			printk(KERN_NOTICE "SAK: killed process %d"
			    " (%s): fd#%d opened to the tty\n",
					    task_pid_nr(p), p->comm, i);
				    task_pid_nr(p), p->comm, i - 1);
			force_sig(SIGKILL, p);
					break;
				}
			}
			spin_unlock(&p->files->file_lock);
		}
		task_unlock(p);
	} while_each_thread(g, p);
+21 −0
Original line number Diff line number Diff line
@@ -979,3 +979,24 @@ int f_dupfd(unsigned int from, struct file *file, unsigned flags)
	}
	return err;
}

int iterate_fd(struct files_struct *files, unsigned n,
		int (*f)(const void *, struct file *, unsigned),
		const void *p)
{
	struct fdtable *fdt;
	struct file *file;
	int res = 0;
	if (!files)
		return 0;
	spin_lock(&files->file_lock);
	fdt = files_fdtable(files);
	while (!res && n < fdt->max_fds) {
		file = rcu_dereference_check_fdtable(files, fdt->fd[n++]);
		if (file)
			res = f(p, file, n);
	}
	spin_unlock(&files->file_lock);
	return res;
}
EXPORT_SYMBOL(iterate_fd);
+3 −0
Original line number Diff line number Diff line
@@ -98,6 +98,9 @@ void reset_files_struct(struct files_struct *);
int unshare_files(struct files_struct **);
struct files_struct *dup_fd(struct files_struct *, int *);
void do_close_on_exec(struct files_struct *);
int iterate_fd(struct files_struct *, unsigned,
		int (*)(const void *, struct file *, unsigned),
		const void *);

extern int __alloc_fd(struct files_struct *files,
		      unsigned start, unsigned end, unsigned flags);
+12 −26
Original line number Diff line number Diff line
@@ -272,38 +272,24 @@ static int write_priomap(struct cgroup *cgrp, struct cftype *cft,
	return ret;
}

static int update_netprio(const void *v, struct file *file, unsigned n)
{
	int err;
	struct socket *sock = sock_from_file(file, &err);
	if (sock)
		sock->sk->sk_cgrp_prioidx = (u32)(unsigned long)v;
	return 0;
}

void net_prio_attach(struct cgroup *cgrp, struct cgroup_taskset *tset)
{
	struct task_struct *p;
	void *v;

	cgroup_taskset_for_each(p, cgrp, tset) {
		unsigned int fd;
		struct fdtable *fdt;
		struct files_struct *files;

		task_lock(p);
		files = p->files;
		if (!files) {
			task_unlock(p);
			continue;
		}

		spin_lock(&files->file_lock);
		fdt = files_fdtable(files);
		for (fd = 0; fd < fdt->max_fds; fd++) {
			struct file *file;
			struct socket *sock;
			int err;

			file = fcheck_files(files, fd);
			if (!file)
				continue;

			sock = sock_from_file(file, &err);
			if (sock)
				sock_update_netprioidx(sock->sk, p);
		}
		spin_unlock(&files->file_lock);
		v = (void *)(unsigned long)task_netprioidx(p);
		iterate_fd(p->files, 0, update_netprio, v);
		task_unlock(p);
	}
}
+22 −35
Original line number Diff line number Diff line
@@ -2088,15 +2088,19 @@ static int selinux_bprm_secureexec(struct linux_binprm *bprm)
	return (atsecure || cap_bprm_secureexec(bprm));
}

static int match_file(const void *p, struct file *file, unsigned fd)
{
	return file_has_perm(p, file, file_to_av(file)) ? fd + 1 : 0;
}

/* Derived from fs/exec.c:flush_old_files. */
static inline void flush_unauthorized_files(const struct cred *cred,
					    struct files_struct *files)
{
	struct file *file, *devnull = NULL;
	struct tty_struct *tty;
	struct fdtable *fdt;
	long j = -1;
	int drop_tty = 0;
	unsigned n;

	tty = get_current_tty();
	if (tty) {
@@ -2123,41 +2127,24 @@ static inline void flush_unauthorized_files(const struct cred *cred,
		no_tty();

	/* Revalidate access to inherited open files. */
	spin_lock(&files->file_lock);
	for (;;) {
		unsigned long set, i;
		j++;
		i = j * BITS_PER_LONG;
		fdt = files_fdtable(files);
		if (i >= fdt->max_fds)
			break;
		set = fdt->open_fds[j];
		if (!set)
			continue;
		spin_unlock(&files->file_lock);
		for ( ; set ; i++, set >>= 1) {
			if (!(set & 1))
				continue;
			file = fget(i);
			if (!file)
				continue;
			if (file_has_perm(cred, file, file_to_av(file))) {
				if (devnull) {
	n = iterate_fd(files, 0, match_file, cred);
	if (!n) /* none found? */
		return;

	devnull = dentry_open(&selinux_null, O_RDWR, cred);
	if (!IS_ERR(devnull)) {
		/* replace all the matching ones with this */
		do {
			get_file(devnull);
			replace_fd(n - 1, devnull, 0);
		} while ((n = iterate_fd(files, n, match_file, cred)) != 0);
		fput(devnull);
	} else {
					devnull = dentry_open(&selinux_null,
								O_RDWR, cred);
					if (IS_ERR(devnull))
						devnull = NULL;
				}
				replace_fd(i, devnull, 0);
			}
			fput(file);
		}
		spin_lock(&files->file_lock);

		/* just close all the matching ones */
		do {
			replace_fd(n - 1, NULL, 0);
		} while ((n = iterate_fd(files, n, match_file, cred)) != 0);
	}
	spin_unlock(&files->file_lock);
}

/*