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:
Родитель
ad47bd7252
Коммит
c3c073f808
|
@ -2791,6 +2791,13 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd,
|
||||||
}
|
}
|
||||||
#endif
|
#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
|
* This implements the "Secure Attention Key" --- the idea is to
|
||||||
* prevent trojan horses by killing all processes associated with this
|
* 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 task_struct *g, *p;
|
||||||
struct pid *session;
|
struct pid *session;
|
||||||
int i;
|
int i;
|
||||||
struct file *filp;
|
|
||||||
struct fdtable *fdt;
|
|
||||||
|
|
||||||
if (!tty)
|
if (!tty)
|
||||||
return;
|
return;
|
||||||
|
@ -2849,27 +2854,12 @@ void __do_SAK(struct tty_struct *tty)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
task_lock(p);
|
task_lock(p);
|
||||||
if (p->files) {
|
i = iterate_fd(p->files, 0, this_tty, tty);
|
||||||
/*
|
if (i != 0) {
|
||||||
* We don't take a ref to the file, so we must
|
printk(KERN_NOTICE "SAK: killed process %d"
|
||||||
* hold ->file_lock instead.
|
" (%s): fd#%d opened to the tty\n",
|
||||||
*/
|
task_pid_nr(p), p->comm, i - 1);
|
||||||
spin_lock(&p->files->file_lock);
|
force_sig(SIGKILL, p);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
task_unlock(p);
|
task_unlock(p);
|
||||||
} while_each_thread(g, 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;
|
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 **);
|
int unshare_files(struct files_struct **);
|
||||||
struct files_struct *dup_fd(struct files_struct *, int *);
|
struct files_struct *dup_fd(struct files_struct *, int *);
|
||||||
void do_close_on_exec(struct files_struct *);
|
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,
|
extern int __alloc_fd(struct files_struct *files,
|
||||||
unsigned start, unsigned end, unsigned flags);
|
unsigned start, unsigned end, unsigned flags);
|
||||||
|
|
|
@ -272,38 +272,24 @@ out_free_devname:
|
||||||
return ret;
|
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)
|
void net_prio_attach(struct cgroup *cgrp, struct cgroup_taskset *tset)
|
||||||
{
|
{
|
||||||
struct task_struct *p;
|
struct task_struct *p;
|
||||||
|
void *v;
|
||||||
|
|
||||||
cgroup_taskset_for_each(p, cgrp, tset) {
|
cgroup_taskset_for_each(p, cgrp, tset) {
|
||||||
unsigned int fd;
|
|
||||||
struct fdtable *fdt;
|
|
||||||
struct files_struct *files;
|
|
||||||
|
|
||||||
task_lock(p);
|
task_lock(p);
|
||||||
files = p->files;
|
v = (void *)(unsigned long)task_netprioidx(p);
|
||||||
if (!files) {
|
iterate_fd(p->files, 0, update_netprio, v);
|
||||||
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);
|
|
||||||
task_unlock(p);
|
task_unlock(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2088,15 +2088,19 @@ static int selinux_bprm_secureexec(struct linux_binprm *bprm)
|
||||||
return (atsecure || cap_bprm_secureexec(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. */
|
/* Derived from fs/exec.c:flush_old_files. */
|
||||||
static inline void flush_unauthorized_files(const struct cred *cred,
|
static inline void flush_unauthorized_files(const struct cred *cred,
|
||||||
struct files_struct *files)
|
struct files_struct *files)
|
||||||
{
|
{
|
||||||
struct file *file, *devnull = NULL;
|
struct file *file, *devnull = NULL;
|
||||||
struct tty_struct *tty;
|
struct tty_struct *tty;
|
||||||
struct fdtable *fdt;
|
|
||||||
long j = -1;
|
|
||||||
int drop_tty = 0;
|
int drop_tty = 0;
|
||||||
|
unsigned n;
|
||||||
|
|
||||||
tty = get_current_tty();
|
tty = get_current_tty();
|
||||||
if (tty) {
|
if (tty) {
|
||||||
|
@ -2123,41 +2127,24 @@ static inline void flush_unauthorized_files(const struct cred *cred,
|
||||||
no_tty();
|
no_tty();
|
||||||
|
|
||||||
/* Revalidate access to inherited open files. */
|
/* Revalidate access to inherited open files. */
|
||||||
spin_lock(&files->file_lock);
|
n = iterate_fd(files, 0, match_file, cred);
|
||||||
for (;;) {
|
if (!n) /* none found? */
|
||||||
unsigned long set, i;
|
return;
|
||||||
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);
|
|
||||||
|
|
||||||
|
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Загрузка…
Ссылка в новой задаче