aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2012-08-21 22:32:06 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2012-09-26 21:09:59 -0400
commitc3c073f808b22dfae15ef8412b6f7b998644139a (patch)
tree3369bcbe414738d90e6ccfe257f6ce3e72f6a5ae
parentad47bd7252bf402fe7dba92f5240b5ed16832ae7 (diff)
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>
-rw-r--r--drivers/tty/tty_io.c36
-rw-r--r--fs/file.c21
-rw-r--r--include/linux/fdtable.h3
-rw-r--r--net/core/netprio_cgroup.c38
-rw-r--r--security/selinux/hooks.c57
5 files changed, 71 insertions, 84 deletions
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index b425c79675ad..71d95cfbabec 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -2791,6 +2791,13 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd,
2791} 2791}
2792#endif 2792#endif
2793 2793
2794static int this_tty(const void *t, struct file *file, unsigned fd)
2795{
2796 if (likely(file->f_op->read != tty_read))
2797 return 0;
2798 return file_tty(file) != t ? 0 : fd + 1;
2799}
2800
2794/* 2801/*
2795 * This implements the "Secure Attention Key" --- the idea is to 2802 * This implements the "Secure Attention Key" --- the idea is to
2796 * prevent trojan horses by killing all processes associated with this 2803 * prevent trojan horses by killing all processes associated with this
@@ -2818,8 +2825,6 @@ void __do_SAK(struct tty_struct *tty)
2818 struct task_struct *g, *p; 2825 struct task_struct *g, *p;
2819 struct pid *session; 2826 struct pid *session;
2820 int i; 2827 int i;
2821 struct file *filp;
2822 struct fdtable *fdt;
2823 2828
2824 if (!tty) 2829 if (!tty)
2825 return; 2830 return;
@@ -2849,27 +2854,12 @@ void __do_SAK(struct tty_struct *tty)
2849 continue; 2854 continue;
2850 } 2855 }
2851 task_lock(p); 2856 task_lock(p);
2852 if (p->files) { 2857 i = iterate_fd(p->files, 0, this_tty, tty);
2853 /* 2858 if (i != 0) {
2854 * We don't take a ref to the file, so we must 2859 printk(KERN_NOTICE "SAK: killed process %d"
2855 * hold ->file_lock instead. 2860 " (%s): fd#%d opened to the tty\n",
2856 */ 2861 task_pid_nr(p), p->comm, i - 1);
2857 spin_lock(&p->files->file_lock); 2862 force_sig(SIGKILL, p);
2858 fdt = files_fdtable(p->files);
2859 for (i = 0; i < fdt->max_fds; i++) {
2860 filp = fcheck_files(p->files, i);
2861 if (!filp)
2862 continue;
2863 if (filp->f_op->read == tty_read &&
2864 file_tty(filp) == tty) {
2865 printk(KERN_NOTICE "SAK: killed process %d"
2866 " (%s): fd#%d opened to the tty\n",
2867 task_pid_nr(p), p->comm, i);
2868 force_sig(SIGKILL, p);
2869 break;
2870 }
2871 }
2872 spin_unlock(&p->files->file_lock);
2873 } 2863 }
2874 task_unlock(p); 2864 task_unlock(p);
2875 } while_each_thread(g, p); 2865 } while_each_thread(g, p);
diff --git a/fs/file.c b/fs/file.c
index 967bd0dadbe5..e6e418122587 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -979,3 +979,24 @@ int f_dupfd(unsigned int from, struct file *file, unsigned flags)
979 } 979 }
980 return err; 980 return err;
981} 981}
982
983int iterate_fd(struct files_struct *files, unsigned n,
984 int (*f)(const void *, struct file *, unsigned),
985 const void *p)
986{
987 struct fdtable *fdt;
988 struct file *file;
989 int res = 0;
990 if (!files)
991 return 0;
992 spin_lock(&files->file_lock);
993 fdt = files_fdtable(files);
994 while (!res && n < fdt->max_fds) {
995 file = rcu_dereference_check_fdtable(files, fdt->fd[n++]);
996 if (file)
997 res = f(p, file, n);
998 }
999 spin_unlock(&files->file_lock);
1000 return res;
1001}
1002EXPORT_SYMBOL(iterate_fd);
diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h
index de2b71caa0f0..fb7dacae0522 100644
--- a/include/linux/fdtable.h
+++ b/include/linux/fdtable.h
@@ -98,6 +98,9 @@ void reset_files_struct(struct files_struct *);
98int unshare_files(struct files_struct **); 98int unshare_files(struct files_struct **);
99struct files_struct *dup_fd(struct files_struct *, int *); 99struct files_struct *dup_fd(struct files_struct *, int *);
100void do_close_on_exec(struct files_struct *); 100void do_close_on_exec(struct files_struct *);
101int iterate_fd(struct files_struct *, unsigned,
102 int (*)(const void *, struct file *, unsigned),
103 const void *);
101 104
102extern int __alloc_fd(struct files_struct *files, 105extern int __alloc_fd(struct files_struct *files,
103 unsigned start, unsigned end, unsigned flags); 106 unsigned start, unsigned end, unsigned flags);
diff --git a/net/core/netprio_cgroup.c b/net/core/netprio_cgroup.c
index c75e3f9d060f..5ffd084c6a83 100644
--- a/net/core/netprio_cgroup.c
+++ b/net/core/netprio_cgroup.c
@@ -272,38 +272,24 @@ out_free_devname:
272 return ret; 272 return ret;
273} 273}
274 274
275static int update_netprio(const void *v, struct file *file, unsigned n)
276{
277 int err;
278 struct socket *sock = sock_from_file(file, &err);
279 if (sock)
280 sock->sk->sk_cgrp_prioidx = (u32)(unsigned long)v;
281 return 0;
282}
283
275void net_prio_attach(struct cgroup *cgrp, struct cgroup_taskset *tset) 284void net_prio_attach(struct cgroup *cgrp, struct cgroup_taskset *tset)
276{ 285{
277 struct task_struct *p; 286 struct task_struct *p;
287 void *v;
278 288
279 cgroup_taskset_for_each(p, cgrp, tset) { 289 cgroup_taskset_for_each(p, cgrp, tset) {
280 unsigned int fd;
281 struct fdtable *fdt;
282 struct files_struct *files;
283
284 task_lock(p); 290 task_lock(p);
285 files = p->files; 291 v = (void *)(unsigned long)task_netprioidx(p);
286 if (!files) { 292 iterate_fd(p->files, 0, update_netprio, v);
287 task_unlock(p);
288 continue;
289 }
290
291 spin_lock(&files->file_lock);
292 fdt = files_fdtable(files);
293 for (fd = 0; fd < fdt->max_fds; fd++) {
294 struct file *file;
295 struct socket *sock;
296 int err;
297
298 file = fcheck_files(files, fd);
299 if (!file)
300 continue;
301
302 sock = sock_from_file(file, &err);
303 if (sock)
304 sock_update_netprioidx(sock->sk, p);
305 }
306 spin_unlock(&files->file_lock);
307 task_unlock(p); 293 task_unlock(p);
308 } 294 }
309} 295}
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 00b50113642d..4dfbcea10eb7 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2088,15 +2088,19 @@ static int selinux_bprm_secureexec(struct linux_binprm *bprm)
2088 return (atsecure || cap_bprm_secureexec(bprm)); 2088 return (atsecure || cap_bprm_secureexec(bprm));
2089} 2089}
2090 2090
2091static int match_file(const void *p, struct file *file, unsigned fd)
2092{
2093 return file_has_perm(p, file, file_to_av(file)) ? fd + 1 : 0;
2094}
2095
2091/* Derived from fs/exec.c:flush_old_files. */ 2096/* Derived from fs/exec.c:flush_old_files. */
2092static inline void flush_unauthorized_files(const struct cred *cred, 2097static inline void flush_unauthorized_files(const struct cred *cred,
2093 struct files_struct *files) 2098 struct files_struct *files)
2094{ 2099{
2095 struct file *file, *devnull = NULL; 2100 struct file *file, *devnull = NULL;
2096 struct tty_struct *tty; 2101 struct tty_struct *tty;
2097 struct fdtable *fdt;
2098 long j = -1;
2099 int drop_tty = 0; 2102 int drop_tty = 0;
2103 unsigned n;
2100 2104
2101 tty = get_current_tty(); 2105 tty = get_current_tty();
2102 if (tty) { 2106 if (tty) {
@@ -2123,41 +2127,24 @@ static inline void flush_unauthorized_files(const struct cred *cred,
2123 no_tty(); 2127 no_tty();
2124 2128
2125 /* Revalidate access to inherited open files. */ 2129 /* Revalidate access to inherited open files. */
2126 spin_lock(&files->file_lock); 2130 n = iterate_fd(files, 0, match_file, cred);
2127 for (;;) { 2131 if (!n) /* none found? */
2128 unsigned long set, i; 2132 return;
2129 j++;
2130 i = j * BITS_PER_LONG;
2131 fdt = files_fdtable(files);
2132 if (i >= fdt->max_fds)
2133 break;
2134 set = fdt->open_fds[j];
2135 if (!set)
2136 continue;
2137 spin_unlock(&files->file_lock);
2138 for ( ; set ; i++, set >>= 1) {
2139 if (!(set & 1))
2140 continue;
2141 file = fget(i);
2142 if (!file)
2143 continue;
2144 if (file_has_perm(cred, file, file_to_av(file))) {
2145 if (devnull) {
2146 get_file(devnull);
2147 } else {
2148 devnull = dentry_open(&selinux_null,
2149 O_RDWR, cred);
2150 if (IS_ERR(devnull))
2151 devnull = NULL;
2152 }
2153 replace_fd(i, devnull, 0);
2154 }
2155 fput(file);
2156 }
2157 spin_lock(&files->file_lock);
2158 2133
2134 devnull = dentry_open(&selinux_null, O_RDWR, cred);
2135 if (!IS_ERR(devnull)) {
2136 /* replace all the matching ones with this */
2137 do {
2138 get_file(devnull);
2139 replace_fd(n - 1, devnull, 0);
2140 } while ((n = iterate_fd(files, n, match_file, cred)) != 0);
2141 fput(devnull);
2142 } else {
2143 /* just close all the matching ones */
2144 do {
2145 replace_fd(n - 1, NULL, 0);
2146 } while ((n = iterate_fd(files, n, match_file, cred)) != 0);
2159 } 2147 }
2160 spin_unlock(&files->file_lock);
2161} 2148}
2162 2149
2163/* 2150/*