Skip to content

Commit

Permalink
[PATCH] sanitize anon_inode_getfd()
Browse files Browse the repository at this point in the history
a) none of the callers even looks at inode or file returned by anon_inode_getfd()
b) any caller that would try to look at those would be racy, since by the time
it returns we might have raced with close() from another thread and that
file would be pining for fjords.

Signed-off-by: Al Viro <[email protected]>
  • Loading branch information
Al Viro committed May 1, 2008
1 parent 9f3acc3 commit 2030a42
Show file tree
Hide file tree
Showing 7 changed files with 29 additions and 74 deletions.
13 changes: 3 additions & 10 deletions fs/anon_inodes.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,6 @@ static struct dentry_operations anon_inodefs_dentry_operations = {
* anonymous inode, and a dentry that describe the "class"
* of the file
*
* @pfd: [out] pointer to the file descriptor
* @dpinode: [out] pointer to the inode
* @pfile: [out] pointer to the file struct
* @name: [in] name of the "class" of the new file
* @fops [in] file operations for the new file
* @priv [in] private data for the new file (will be file's private_data)
Expand All @@ -68,10 +65,9 @@ static struct dentry_operations anon_inodefs_dentry_operations = {
* that do not need to have a full-fledged inode in order to operate correctly.
* All the files created with anon_inode_getfd() will share a single inode,
* hence saving memory and avoiding code duplication for the file/inode/dentry
* setup.
* setup. Returns new descriptor or -error.
*/
int anon_inode_getfd(int *pfd, struct inode **pinode, struct file **pfile,
const char *name, const struct file_operations *fops,
int anon_inode_getfd(const char *name, const struct file_operations *fops,
void *priv)
{
struct qstr this;
Expand Down Expand Up @@ -125,10 +121,7 @@ int anon_inode_getfd(int *pfd, struct inode **pinode, struct file **pfile,

fd_install(fd, file);

*pfd = fd;
*pinode = anon_inode_inode;
*pfile = file;
return 0;
return fd;

err_dput:
dput(dentry);
Expand Down
15 changes: 5 additions & 10 deletions fs/eventfd.c
Original file line number Diff line number Diff line change
Expand Up @@ -200,10 +200,8 @@ struct file *eventfd_fget(int fd)

asmlinkage long sys_eventfd(unsigned int count)
{
int error, fd;
int fd;
struct eventfd_ctx *ctx;
struct file *file;
struct inode *inode;

ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
if (!ctx)
Expand All @@ -216,12 +214,9 @@ asmlinkage long sys_eventfd(unsigned int count)
* When we call this, the initialization must be complete, since
* anon_inode_getfd() will install the fd.
*/
error = anon_inode_getfd(&fd, &inode, &file, "[eventfd]",
&eventfd_fops, ctx);
if (!error)
return fd;

kfree(ctx);
return error;
fd = anon_inode_getfd("[eventfd]", &eventfd_fops, ctx);
if (fd < 0)
kfree(ctx);
return fd;
}

23 changes: 8 additions & 15 deletions fs/eventpoll.c
Original file line number Diff line number Diff line change
Expand Up @@ -1050,8 +1050,6 @@ asmlinkage long sys_epoll_create(int size)
{
int error, fd = -1;
struct eventpoll *ep;
struct inode *inode;
struct file *file;

DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d)\n",
current, size));
Expand All @@ -1061,29 +1059,24 @@ asmlinkage long sys_epoll_create(int size)
* structure ( "struct eventpoll" ).
*/
error = -EINVAL;
if (size <= 0 || (error = ep_alloc(&ep)) != 0)
if (size <= 0 || (error = ep_alloc(&ep)) < 0) {
fd = error;
goto error_return;
}

/*
* Creates all the items needed to setup an eventpoll file. That is,
* a file structure, and inode and a free file descriptor.
* a file structure and a free file descriptor.
*/
error = anon_inode_getfd(&fd, &inode, &file, "[eventpoll]",
&eventpoll_fops, ep);
if (error)
goto error_free;
fd = anon_inode_getfd("[eventpoll]", &eventpoll_fops, ep);
if (fd < 0)
ep_free(ep);

error_return:
DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d) = %d\n",
current, size, fd));

return fd;

error_free:
ep_free(ep);
error_return:
DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d) = %d\n",
current, size, error));
return error;
}

/*
Expand Down
17 changes: 4 additions & 13 deletions fs/signalfd.c
Original file line number Diff line number Diff line change
Expand Up @@ -207,11 +207,8 @@ static const struct file_operations signalfd_fops = {

asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t sizemask)
{
int error;
sigset_t sigmask;
struct signalfd_ctx *ctx;
struct file *file;
struct inode *inode;

if (sizemask != sizeof(sigset_t) ||
copy_from_user(&sigmask, user_mask, sizeof(sigmask)))
Expand All @@ -230,12 +227,11 @@ asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t sizemas
* When we call this, the initialization must be complete, since
* anon_inode_getfd() will install the fd.
*/
error = anon_inode_getfd(&ufd, &inode, &file, "[signalfd]",
&signalfd_fops, ctx);
if (error)
goto err_fdalloc;
ufd = anon_inode_getfd("[signalfd]", &signalfd_fops, ctx);
if (ufd < 0)
kfree(ctx);
} else {
file = fget(ufd);
struct file *file = fget(ufd);
if (!file)
return -EBADF;
ctx = file->private_data;
Expand All @@ -252,9 +248,4 @@ asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t sizemas
}

return ufd;

err_fdalloc:
kfree(ctx);
return error;
}

11 changes: 3 additions & 8 deletions fs/timerfd.c
Original file line number Diff line number Diff line change
Expand Up @@ -181,10 +181,8 @@ static struct file *timerfd_fget(int fd)

asmlinkage long sys_timerfd_create(int clockid, int flags)
{
int error, ufd;
int ufd;
struct timerfd_ctx *ctx;
struct file *file;
struct inode *inode;

if (flags)
return -EINVAL;
Expand All @@ -200,12 +198,9 @@ asmlinkage long sys_timerfd_create(int clockid, int flags)
ctx->clockid = clockid;
hrtimer_init(&ctx->tmr, clockid, HRTIMER_MODE_ABS);

error = anon_inode_getfd(&ufd, &inode, &file, "[timerfd]",
&timerfd_fops, ctx);
if (error) {
ufd = anon_inode_getfd("[timerfd]", &timerfd_fops, ctx);
if (ufd < 0)
kfree(ctx);
return error;
}

return ufd;
}
Expand Down
3 changes: 1 addition & 2 deletions include/linux/anon_inodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@
#ifndef _LINUX_ANON_INODES_H
#define _LINUX_ANON_INODES_H

int anon_inode_getfd(int *pfd, struct inode **pinode, struct file **pfile,
const char *name, const struct file_operations *fops,
int anon_inode_getfd(const char *name, const struct file_operations *fops,
void *priv);

#endif /* _LINUX_ANON_INODES_H */
Expand Down
21 changes: 5 additions & 16 deletions virt/kvm/kvm_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -834,16 +834,9 @@ static const struct file_operations kvm_vcpu_fops = {
*/
static int create_vcpu_fd(struct kvm_vcpu *vcpu)
{
int fd, r;
struct inode *inode;
struct file *file;

r = anon_inode_getfd(&fd, &inode, &file,
"kvm-vcpu", &kvm_vcpu_fops, vcpu);
if (r) {
int fd = anon_inode_getfd("kvm-vcpu", &kvm_vcpu_fops, vcpu);
if (fd < 0)
kvm_put_kvm(vcpu->kvm);
return r;
}
return fd;
}

Expand Down Expand Up @@ -1168,19 +1161,15 @@ static const struct file_operations kvm_vm_fops = {

static int kvm_dev_ioctl_create_vm(void)
{
int fd, r;
struct inode *inode;
struct file *file;
int fd;
struct kvm *kvm;

kvm = kvm_create_vm();
if (IS_ERR(kvm))
return PTR_ERR(kvm);
r = anon_inode_getfd(&fd, &inode, &file, "kvm-vm", &kvm_vm_fops, kvm);
if (r) {
fd = anon_inode_getfd("kvm-vm", &kvm_vm_fops, kvm);
if (fd < 0)
kvm_put_kvm(kvm);
return r;
}

return fd;
}
Expand Down

0 comments on commit 2030a42

Please sign in to comment.