From 28407630513b1a86133db0ef8b39fabad6c494af Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 17 Aug 2012 23:54:15 -0400 Subject: take descriptor handling from sock_alloc_file() to callers Signed-off-by: Al Viro --- net/socket.c | 62 +++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 40 insertions(+), 22 deletions(-) (limited to 'net') diff --git a/net/socket.c b/net/socket.c index edc3c4af9085..a14ec19164b6 100644 --- a/net/socket.c +++ b/net/socket.c @@ -346,22 +346,15 @@ static struct file_system_type sock_fs_type = { * but we take care of internal coherence yet. */ -static int sock_alloc_file(struct socket *sock, struct file **f, int flags) +static struct file *sock_alloc_file(struct socket *sock, int flags) { struct qstr name = { .name = "" }; struct path path; struct file *file; - int fd; - - fd = get_unused_fd_flags(flags); - if (unlikely(fd < 0)) - return fd; path.dentry = d_alloc_pseudo(sock_mnt->mnt_sb, &name); - if (unlikely(!path.dentry)) { - put_unused_fd(fd); - return -ENOMEM; - } + if (unlikely(!path.dentry)) + return ERR_PTR(-ENOMEM); path.mnt = mntget(sock_mnt); d_instantiate(path.dentry, SOCK_INODE(sock)); @@ -373,28 +366,31 @@ static int sock_alloc_file(struct socket *sock, struct file **f, int flags) /* drop dentry, keep inode */ ihold(path.dentry->d_inode); path_put(&path); - put_unused_fd(fd); - return -ENFILE; + return ERR_PTR(-ENFILE); } sock->file = file; file->f_flags = O_RDWR | (flags & O_NONBLOCK); file->f_pos = 0; file->private_data = sock; - - *f = file; - return fd; + return file; } int sock_map_fd(struct socket *sock, int flags) { struct file *newfile; - int fd = sock_alloc_file(sock, &newfile, flags); + int fd = get_unused_fd_flags(flags); + if (unlikely(fd < 0)) + return fd; - if (likely(fd >= 0)) + newfile = sock_alloc_file(sock, flags); + if (likely(!IS_ERR(newfile))) { fd_install(fd, newfile); + return fd; + } - return fd; + put_unused_fd(fd); + return PTR_ERR(newfile); } EXPORT_SYMBOL(sock_map_fd); @@ -1394,17 +1390,32 @@ SYSCALL_DEFINE4(socketpair, int, family, int, type, int, protocol, if (err < 0) goto out_release_both; - fd1 = sock_alloc_file(sock1, &newfile1, flags); + fd1 = get_unused_fd_flags(flags); if (unlikely(fd1 < 0)) { err = fd1; goto out_release_both; } - - fd2 = sock_alloc_file(sock2, &newfile2, flags); + fd2 = get_unused_fd_flags(flags); if (unlikely(fd2 < 0)) { err = fd2; + put_unused_fd(fd1); + goto out_release_both; + } + + newfile1 = sock_alloc_file(sock1, flags); + if (unlikely(IS_ERR(newfile1))) { + err = PTR_ERR(newfile1); + put_unused_fd(fd1); + put_unused_fd(fd2); + goto out_release_both; + } + + newfile2 = sock_alloc_file(sock2, flags); + if (IS_ERR(newfile2)) { + err = PTR_ERR(newfile2); fput(newfile1); put_unused_fd(fd1); + put_unused_fd(fd2); sock_release(sock2); goto out; } @@ -1536,12 +1547,19 @@ SYSCALL_DEFINE4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr, */ __module_get(newsock->ops->owner); - newfd = sock_alloc_file(newsock, &newfile, flags); + newfd = get_unused_fd_flags(flags); if (unlikely(newfd < 0)) { err = newfd; sock_release(newsock); goto out_put; } + newfile = sock_alloc_file(newsock, flags); + if (unlikely(IS_ERR(newfile))) { + err = PTR_ERR(newfile); + put_unused_fd(newfd); + sock_release(newsock); + goto out_put; + } err = security_socket_accept(sock, newsock); if (err) -- cgit v1.2.3 From 56b31d1c9f1e6a3ad92e7bfe252721e05d92b285 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 18 Aug 2012 00:25:51 -0400 Subject: unexport sock_map_fd(), switch to sock_alloc_file() Both modular callers of sock_map_fd() had been buggy; sctp one leaks descriptor and file if copy_to_user() fails, 9p one shouldn't be exposing file in the descriptor table at all. Switch both to sock_alloc_file(), export it, unexport sock_map_fd() and make it static. Signed-off-by: Al Viro --- include/linux/net.h | 3 ++- net/9p/trans_fd.c | 16 +++++++--------- net/sctp/socket.c | 25 ++++++++++++++++++++----- net/socket.c | 6 +++--- 4 files changed, 32 insertions(+), 18 deletions(-) (limited to 'net') diff --git a/include/linux/net.h b/include/linux/net.h index 99276c3dc89a..c8a9708d4d66 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -65,6 +65,7 @@ typedef enum { struct poll_table_struct; struct pipe_inode_info; struct inode; +struct file; struct net; #define SOCK_ASYNC_NOSPACE 0 @@ -246,7 +247,7 @@ extern int sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t len); extern int sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t size, int flags); -extern int sock_map_fd(struct socket *sock, int flags); +extern struct file *sock_alloc_file(struct socket *sock, int flags); extern struct socket *sockfd_lookup(int fd, int *err); extern struct socket *sock_from_file(struct file *file, int *err); #define sockfd_put(sock) fput(sock->file) diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c index 6449bae15702..8c4e0b538a8a 100644 --- a/net/9p/trans_fd.c +++ b/net/9p/trans_fd.c @@ -793,30 +793,28 @@ static int p9_fd_open(struct p9_client *client, int rfd, int wfd) static int p9_socket_open(struct p9_client *client, struct socket *csocket) { struct p9_trans_fd *p; - int ret, fd; + struct file *file; + int ret; p = kmalloc(sizeof(struct p9_trans_fd), GFP_KERNEL); if (!p) return -ENOMEM; csocket->sk->sk_allocation = GFP_NOIO; - fd = sock_map_fd(csocket, 0); - if (fd < 0) { + file = sock_alloc_file(csocket, 0); + if (IS_ERR(file)) { pr_err("%s (%d): failed to map fd\n", __func__, task_pid_nr(current)); sock_release(csocket); kfree(p); - return fd; + return PTR_ERR(file); } - get_file(csocket->file); - get_file(csocket->file); - p->wr = p->rd = csocket->file; + get_file(file); + p->wr = p->rd = file; client->trans = p; client->status = Connected; - sys_close(fd); /* still racy */ - p->rd->f_flags |= O_NONBLOCK; p->conn = p9_conn_create(client); diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 5e259817a7f3..fb5931ca50d0 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -70,6 +70,7 @@ #include #include #include +#include #include #include @@ -4276,6 +4277,7 @@ static int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval { sctp_peeloff_arg_t peeloff; struct socket *newsock; + struct file *newfile; int retval = 0; if (len < sizeof(sctp_peeloff_arg_t)) @@ -4289,22 +4291,35 @@ static int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval goto out; /* Map the socket to an unused fd that can be returned to the user. */ - retval = sock_map_fd(newsock, 0); + retval = get_unused_fd(); if (retval < 0) { sock_release(newsock); goto out; } + newfile = sock_alloc_file(newsock, 0); + if (unlikely(IS_ERR(newfile))) { + put_unused_fd(retval); + sock_release(newsock); + return PTR_ERR(newfile); + } + SCTP_DEBUG_PRINTK("%s: sk: %p newsk: %p sd: %d\n", __func__, sk, newsock->sk, retval); /* Return the fd mapped to the new socket. */ + if (put_user(len, optlen)) { + fput(newfile); + put_unused_fd(retval); + return -EFAULT; + } peeloff.sd = retval; - if (put_user(len, optlen)) + if (copy_to_user(optval, &peeloff, len)) { + fput(newfile); + put_unused_fd(retval); return -EFAULT; - if (copy_to_user(optval, &peeloff, len)) - retval = -EFAULT; - + } + fd_install(retval, newfile); out: return retval; } diff --git a/net/socket.c b/net/socket.c index a14ec19164b6..38a14311f3a6 100644 --- a/net/socket.c +++ b/net/socket.c @@ -346,7 +346,7 @@ static struct file_system_type sock_fs_type = { * but we take care of internal coherence yet. */ -static struct file *sock_alloc_file(struct socket *sock, int flags) +struct file *sock_alloc_file(struct socket *sock, int flags) { struct qstr name = { .name = "" }; struct path path; @@ -375,8 +375,9 @@ static struct file *sock_alloc_file(struct socket *sock, int flags) file->private_data = sock; return file; } +EXPORT_SYMBOL(sock_alloc_file); -int sock_map_fd(struct socket *sock, int flags) +static int sock_map_fd(struct socket *sock, int flags) { struct file *newfile; int fd = get_unused_fd_flags(flags); @@ -392,7 +393,6 @@ int sock_map_fd(struct socket *sock, int flags) put_unused_fd(fd); return PTR_ERR(newfile); } -EXPORT_SYMBOL(sock_map_fd); struct socket *sock_from_file(struct file *file, int *err) { -- cgit v1.2.3 From c3c073f808b22dfae15ef8412b6f7b998644139a Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 21 Aug 2012 22:32:06 -0400 Subject: 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 --- drivers/tty/tty_io.c | 36 +++++++++++------------------- fs/file.c | 21 +++++++++++++++++ include/linux/fdtable.h | 3 +++ net/core/netprio_cgroup.c | 38 ++++++++++--------------------- security/selinux/hooks.c | 57 ++++++++++++++++++----------------------------- 5 files changed, 71 insertions(+), 84 deletions(-) (limited to 'net') 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, } #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); 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) } 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); 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 *); 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); 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: 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); } } 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) 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); } /* -- cgit v1.2.3 From cb0942b81249798e15c3f04eee2946ef543e8115 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 27 Aug 2012 14:48:26 -0400 Subject: make get_file() return its argument simplifies a bunch of callers... Signed-off-by: Al Viro --- arch/ia64/kernel/perfmon.c | 4 +--- drivers/base/dma-buf.c | 3 +-- drivers/staging/omapdrm/omap_gem.c | 3 +-- drivers/tty/tty_io.c | 9 +++------ fs/autofs4/waitq.c | 3 +-- fs/fuse/dev.c | 3 +-- fs/nfsd/nfs4state.c | 3 +-- fs/proc/base.c | 3 +-- fs/select.c | 3 +-- include/linux/fs.h | 6 +++++- mm/fremap.c | 3 +-- mm/mmap.c | 3 +-- mm/nommu.c | 6 ++---- net/compat.c | 3 +-- net/core/scm.c | 3 +-- security/selinux/hooks.c | 3 +-- 16 files changed, 23 insertions(+), 38 deletions(-) (limited to 'net') diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c index 79826c13b8b6..ff5d4e4c3733 100644 --- a/arch/ia64/kernel/perfmon.c +++ b/arch/ia64/kernel/perfmon.c @@ -2306,7 +2306,7 @@ pfm_smpl_buffer_alloc(struct task_struct *task, struct file *filp, pfm_context_t * partially initialize the vma for the sampling buffer */ vma->vm_mm = mm; - vma->vm_file = filp; + vma->vm_file = get_file(filp); vma->vm_flags = VM_READ| VM_MAYREAD |VM_RESERVED; vma->vm_page_prot = PAGE_READONLY; /* XXX may need to change */ @@ -2345,8 +2345,6 @@ pfm_smpl_buffer_alloc(struct task_struct *task, struct file *filp, pfm_context_t goto error; } - get_file(filp); - /* * now insert the vma in the vm list for the process, must be * done with mmap lock held diff --git a/drivers/base/dma-buf.c b/drivers/base/dma-buf.c index c30f3e1d0efc..460e22dee36d 100644 --- a/drivers/base/dma-buf.c +++ b/drivers/base/dma-buf.c @@ -460,8 +460,7 @@ int dma_buf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma, if (vma->vm_file) fput(vma->vm_file); - vma->vm_file = dmabuf->file; - get_file(vma->vm_file); + vma->vm_file = get_file(dmabuf->file); vma->vm_pgoff = pgoff; diff --git a/drivers/staging/omapdrm/omap_gem.c b/drivers/staging/omapdrm/omap_gem.c index 3a0d035a9e03..2a6bb7f9ee68 100644 --- a/drivers/staging/omapdrm/omap_gem.c +++ b/drivers/staging/omapdrm/omap_gem.c @@ -566,9 +566,8 @@ int omap_gem_mmap_obj(struct drm_gem_object *obj, * in particular in the case of mmap'd dmabufs) */ fput(vma->vm_file); - get_file(obj->filp); vma->vm_pgoff = 0; - vma->vm_file = obj->filp; + vma->vm_file = get_file(obj->filp); vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); } diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 71d95cfbabec..c7561f29d894 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -1163,10 +1163,8 @@ ssize_t redirected_tty_write(struct file *file, const char __user *buf, struct file *p = NULL; spin_lock(&redirect_lock); - if (redirect) { - get_file(redirect); - p = redirect; - } + if (redirect) + p = get_file(redirect); spin_unlock(&redirect_lock); if (p) { @@ -2246,8 +2244,7 @@ static int tioccons(struct file *file) spin_unlock(&redirect_lock); return -EBUSY; } - get_file(file); - redirect = file; + redirect = get_file(file); spin_unlock(&redirect_lock); return 0; } diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c index da8876d38a7b..dce436e595c1 100644 --- a/fs/autofs4/waitq.c +++ b/fs/autofs4/waitq.c @@ -175,8 +175,7 @@ static void autofs4_notify_daemon(struct autofs_sb_info *sbi, return; } - pipe = sbi->pipe; - get_file(pipe); + pipe = get_file(sbi->pipe); mutex_unlock(&sbi->wq_mutex); diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index f4246cfc8d87..8c23fa7a91e6 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -148,8 +148,7 @@ static struct fuse_req *get_reserved_req(struct fuse_conn *fc, if (ff->reserved_req) { req = ff->reserved_req; ff->reserved_req = NULL; - get_file(file); - req->stolen_file = file; + req->stolen_file = get_file(file); } spin_unlock(&fc->lock); } while (!req); diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index cc894eda385a..48a1bad37334 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -2837,8 +2837,7 @@ static int nfs4_setlease(struct nfs4_delegation *dp, int flag) return -ENOMEM; } fp->fi_lease = fl; - fp->fi_deleg_file = fl->fl_file; - get_file(fp->fi_deleg_file); + fp->fi_deleg_file = get_file(fl->fl_file); atomic_set(&fp->fi_delegees, 1); list_add(&dp->dl_perfile, &fp->fi_delegations); return 0; diff --git a/fs/proc/base.c b/fs/proc/base.c index b55c3bb298e3..f1e8438d21b5 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -1979,8 +1979,7 @@ proc_map_files_readdir(struct file *filp, void *dirent, filldir_t filldir) if (++pos <= filp->f_pos) continue; - get_file(vma->vm_file); - info.file = vma->vm_file; + info.file = get_file(vma->vm_file); info.len = snprintf(info.name, sizeof(info.name), "%lx-%lx", vma->vm_start, vma->vm_end); diff --git a/fs/select.c b/fs/select.c index db14c781335e..ffdd16d6e691 100644 --- a/fs/select.c +++ b/fs/select.c @@ -220,8 +220,7 @@ static void __pollwait(struct file *filp, wait_queue_head_t *wait_address, struct poll_table_entry *entry = poll_get_entry(pwq); if (!entry) return; - get_file(filp); - entry->filp = filp; + entry->filp = get_file(filp); entry->wait_address = wait_address; entry->key = p->_key; init_waitqueue_func_entry(&entry->wait, pollwake); diff --git a/include/linux/fs.h b/include/linux/fs.h index aa110476a95b..de1db1c12080 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1074,7 +1074,11 @@ struct file_handle { unsigned char f_handle[0]; }; -#define get_file(x) atomic_long_inc(&(x)->f_count) +static inline struct file *get_file(struct file *f) +{ + atomic_long_inc(&f->f_count); + return f; +} #define fput_atomic(x) atomic_long_add_unless(&(x)->f_count, -1, 1) #define file_count(x) atomic_long_read(&(x)->f_count) diff --git a/mm/fremap.c b/mm/fremap.c index 9ed4fd432467..048659c0c03d 100644 --- a/mm/fremap.c +++ b/mm/fremap.c @@ -195,10 +195,9 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size, */ if (mapping_cap_account_dirty(mapping)) { unsigned long addr; - struct file *file = vma->vm_file; + struct file *file = get_file(vma->vm_file); flags &= MAP_NONBLOCK; - get_file(file); addr = mmap_region(file, start, size, flags, vma->vm_flags, pgoff); fput(file); diff --git a/mm/mmap.c b/mm/mmap.c index ae18a48e7e4e..872441e81914 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1301,8 +1301,7 @@ munmap_back: goto free_vma; correct_wcount = 1; } - vma->vm_file = file; - get_file(file); + vma->vm_file = get_file(file); error = file->f_op->mmap(file, vma); if (error) goto unmap_and_free_vma; diff --git a/mm/nommu.c b/mm/nommu.c index d4b0c10872de..dee2ff89fd58 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -1282,10 +1282,8 @@ unsigned long do_mmap_pgoff(struct file *file, vma->vm_pgoff = pgoff; if (file) { - region->vm_file = file; - get_file(file); - vma->vm_file = file; - get_file(file); + region->vm_file = get_file(file); + vma->vm_file = get_file(file); if (vm_flags & VM_EXECUTABLE) { added_exe_file_vma(current->mm); vma->vm_mm = current->mm; diff --git a/net/compat.c b/net/compat.c index 74ed1d7a84a2..79ae88485001 100644 --- a/net/compat.c +++ b/net/compat.c @@ -301,8 +301,7 @@ void scm_detach_fds_compat(struct msghdr *kmsg, struct scm_cookie *scm) break; } /* Bump the usage count and install the file. */ - get_file(fp[i]); - fd_install(new_fd, fp[i]); + fd_install(new_fd, get_file(fp[i])); } if (i > 0) { diff --git a/net/core/scm.c b/net/core/scm.c index 040cebeed45b..b0098d259233 100644 --- a/net/core/scm.c +++ b/net/core/scm.c @@ -281,11 +281,10 @@ void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm) break; } /* Bump the usage count and install the file. */ - get_file(fp[i]); sock = sock_from_file(fp[i], &err); if (sock) sock_update_netprioidx(sock->sk, current); - fd_install(new_fd, fp[i]); + fd_install(new_fd, get_file(fp[i])); } if (i > 0) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 4dfbcea10eb7..651d8456611a 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2135,8 +2135,7 @@ static inline void flush_unauthorized_files(const struct cred *cred, if (!IS_ERR(devnull)) { /* replace all the matching ones with this */ do { - get_file(devnull); - replace_fd(n - 1, devnull, 0); + replace_fd(n - 1, get_file(devnull), 0); } while ((n = iterate_fd(files, n, match_file, cred)) != 0); fput(devnull); } else { -- cgit v1.2.3