dect
/
linux-2.6
Archived
13
0
Fork 0

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 <viro@zeniv.linux.org.uk>
This commit is contained in:
Al Viro 2012-08-18 00:25:51 -04:00
parent 2840763051
commit 56b31d1c9f
4 changed files with 33 additions and 19 deletions

View File

@ -65,6 +65,7 @@ typedef enum {
struct poll_table_struct; struct poll_table_struct;
struct pipe_inode_info; struct pipe_inode_info;
struct inode; struct inode;
struct file;
struct net; struct net;
#define SOCK_ASYNC_NOSPACE 0 #define SOCK_ASYNC_NOSPACE 0
@ -246,7 +247,7 @@ extern int sock_sendmsg(struct socket *sock, struct msghdr *msg,
size_t len); size_t len);
extern int sock_recvmsg(struct socket *sock, struct msghdr *msg, extern int sock_recvmsg(struct socket *sock, struct msghdr *msg,
size_t size, int flags); 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 *sockfd_lookup(int fd, int *err);
extern struct socket *sock_from_file(struct file *file, int *err); extern struct socket *sock_from_file(struct file *file, int *err);
#define sockfd_put(sock) fput(sock->file) #define sockfd_put(sock) fput(sock->file)

View File

@ -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) static int p9_socket_open(struct p9_client *client, struct socket *csocket)
{ {
struct p9_trans_fd *p; struct p9_trans_fd *p;
int ret, fd; struct file *file;
int ret;
p = kmalloc(sizeof(struct p9_trans_fd), GFP_KERNEL); p = kmalloc(sizeof(struct p9_trans_fd), GFP_KERNEL);
if (!p) if (!p)
return -ENOMEM; return -ENOMEM;
csocket->sk->sk_allocation = GFP_NOIO; csocket->sk->sk_allocation = GFP_NOIO;
fd = sock_map_fd(csocket, 0); file = sock_alloc_file(csocket, 0);
if (fd < 0) { if (IS_ERR(file)) {
pr_err("%s (%d): failed to map fd\n", pr_err("%s (%d): failed to map fd\n",
__func__, task_pid_nr(current)); __func__, task_pid_nr(current));
sock_release(csocket); sock_release(csocket);
kfree(p); kfree(p);
return fd; return PTR_ERR(file);
} }
get_file(csocket->file); get_file(file);
get_file(csocket->file); p->wr = p->rd = file;
p->wr = p->rd = csocket->file;
client->trans = p; client->trans = p;
client->status = Connected; client->status = Connected;
sys_close(fd); /* still racy */
p->rd->f_flags |= O_NONBLOCK; p->rd->f_flags |= O_NONBLOCK;
p->conn = p9_conn_create(client); p->conn = p9_conn_create(client);

View File

@ -70,6 +70,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/crypto.h> #include <linux/crypto.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/file.h>
#include <net/ip.h> #include <net/ip.h>
#include <net/icmp.h> #include <net/icmp.h>
@ -4276,6 +4277,7 @@ static int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval
{ {
sctp_peeloff_arg_t peeloff; sctp_peeloff_arg_t peeloff;
struct socket *newsock; struct socket *newsock;
struct file *newfile;
int retval = 0; int retval = 0;
if (len < sizeof(sctp_peeloff_arg_t)) 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; goto out;
/* Map the socket to an unused fd that can be returned to the user. */ /* 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) { if (retval < 0) {
sock_release(newsock); sock_release(newsock);
goto out; 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", SCTP_DEBUG_PRINTK("%s: sk: %p newsk: %p sd: %d\n",
__func__, sk, newsock->sk, retval); __func__, sk, newsock->sk, retval);
/* Return the fd mapped to the new socket. */ /* Return the fd mapped to the new socket. */
peeloff.sd = retval; if (put_user(len, optlen)) {
if (put_user(len, optlen)) fput(newfile);
put_unused_fd(retval);
return -EFAULT; return -EFAULT;
if (copy_to_user(optval, &peeloff, len)) }
retval = -EFAULT; peeloff.sd = retval;
if (copy_to_user(optval, &peeloff, len)) {
fput(newfile);
put_unused_fd(retval);
return -EFAULT;
}
fd_install(retval, newfile);
out: out:
return retval; return retval;
} }

View File

@ -346,7 +346,7 @@ static struct file_system_type sock_fs_type = {
* but we take care of internal coherence yet. * 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 qstr name = { .name = "" };
struct path path; struct path path;
@ -375,8 +375,9 @@ static struct file *sock_alloc_file(struct socket *sock, int flags)
file->private_data = sock; file->private_data = sock;
return file; 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; struct file *newfile;
int fd = get_unused_fd_flags(flags); int fd = get_unused_fd_flags(flags);
@ -392,7 +393,6 @@ int sock_map_fd(struct socket *sock, int flags)
put_unused_fd(fd); put_unused_fd(fd);
return PTR_ERR(newfile); return PTR_ERR(newfile);
} }
EXPORT_SYMBOL(sock_map_fd);
struct socket *sock_from_file(struct file *file, int *err) struct socket *sock_from_file(struct file *file, int *err)
{ {