mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-09-18 22:14:16 +00:00 
			
		
		
		
	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: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
		
							parent
							
								
									ad47bd7252
								
							
						
					
					
						commit
						c3c073f808
					
				
					 5 changed files with 71 additions and 84 deletions
				
			
		|  | @ -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) { | ||||
| 					printk(KERN_NOTICE "SAK: killed process %d" | ||||
| 					    " (%s): fd#%d opened to the tty\n", | ||||
| 					    task_pid_nr(p), p->comm, i); | ||||
| 					force_sig(SIGKILL, p); | ||||
| 					break; | ||||
| 				} | ||||
| 			} | ||||
| 			spin_unlock(&p->files->file_lock); | ||||
| 		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 - 1); | ||||
| 			force_sig(SIGKILL, p); | ||||
| 		} | ||||
| 		task_unlock(p); | ||||
| 	} while_each_thread(g, p); | ||||
|  |  | |||
							
								
								
									
										21
									
								
								fs/file.c
									
										
									
									
									
								
							
							
						
						
									
										21
									
								
								fs/file.c
									
										
									
									
									
								
							|  | @ -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); | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
|  | @ -272,38 +272,24 @@ out_free_devname: | |||
| 	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); | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -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) { | ||||
| 					get_file(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); | ||||
| 	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 { | ||||
| 		/* 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); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Al Viro
						Al Viro