diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2012-08-21 22:32:06 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2012-09-26 21:09:59 -0400 |
commit | c3c073f808b22dfae15ef8412b6f7b998644139a (patch) | |
tree | 3369bcbe414738d90e6ccfe257f6ce3e72f6a5ae | |
parent | ad47bd7252bf402fe7dba92f5240b5ed16832ae7 (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.c | 36 | ||||
-rw-r--r-- | fs/file.c | 21 | ||||
-rw-r--r-- | include/linux/fdtable.h | 3 | ||||
-rw-r--r-- | net/core/netprio_cgroup.c | 38 | ||||
-rw-r--r-- | security/selinux/hooks.c | 57 |
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 | ||
2794 | static 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); |
@@ -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 | |||
983 | int 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 | } | ||
1002 | EXPORT_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 *); | |||
98 | int unshare_files(struct files_struct **); | 98 | int unshare_files(struct files_struct **); |
99 | struct files_struct *dup_fd(struct files_struct *, int *); | 99 | struct files_struct *dup_fd(struct files_struct *, int *); |
100 | void do_close_on_exec(struct files_struct *); | 100 | void do_close_on_exec(struct files_struct *); |
101 | int iterate_fd(struct files_struct *, unsigned, | ||
102 | int (*)(const void *, struct file *, unsigned), | ||
103 | const void *); | ||
101 | 104 | ||
102 | extern int __alloc_fd(struct files_struct *files, | 105 | extern 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 | ||
275 | static 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 | |||
275 | void net_prio_attach(struct cgroup *cgrp, struct cgroup_taskset *tset) | 284 | void 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 | ||
2091 | static 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. */ |
2092 | static inline void flush_unauthorized_files(const struct cred *cred, | 2097 | static 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 | /* |