aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2012-08-18 00:25:51 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2012-09-26 21:08:50 -0400
commit56b31d1c9f1e6a3ad92e7bfe252721e05d92b285 (patch)
tree44521dbcdf51695b6092f2a4dabe83f460c2ed7c
parent28407630513b1a86133db0ef8b39fabad6c494af (diff)
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>
-rw-r--r--include/linux/net.h3
-rw-r--r--net/9p/trans_fd.c16
-rw-r--r--net/sctp/socket.c25
-rw-r--r--net/socket.c6
4 files changed, 32 insertions, 18 deletions
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 {
65struct poll_table_struct; 65struct poll_table_struct;
66struct pipe_inode_info; 66struct pipe_inode_info;
67struct inode; 67struct inode;
68struct file;
68struct net; 69struct net;
69 70
70#define SOCK_ASYNC_NOSPACE 0 71#define SOCK_ASYNC_NOSPACE 0
@@ -246,7 +247,7 @@ extern int sock_sendmsg(struct socket *sock, struct msghdr *msg,
246 size_t len); 247 size_t len);
247extern int sock_recvmsg(struct socket *sock, struct msghdr *msg, 248extern int sock_recvmsg(struct socket *sock, struct msghdr *msg,
248 size_t size, int flags); 249 size_t size, int flags);
249extern int sock_map_fd(struct socket *sock, int flags); 250extern struct file *sock_alloc_file(struct socket *sock, int flags);
250extern struct socket *sockfd_lookup(int fd, int *err); 251extern struct socket *sockfd_lookup(int fd, int *err);
251extern struct socket *sock_from_file(struct file *file, int *err); 252extern struct socket *sock_from_file(struct file *file, int *err);
252#define sockfd_put(sock) fput(sock->file) 253#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)
793static int p9_socket_open(struct p9_client *client, struct socket *csocket) 793static int p9_socket_open(struct p9_client *client, struct socket *csocket)
794{ 794{
795 struct p9_trans_fd *p; 795 struct p9_trans_fd *p;
796 int ret, fd; 796 struct file *file;
797 int ret;
797 798
798 p = kmalloc(sizeof(struct p9_trans_fd), GFP_KERNEL); 799 p = kmalloc(sizeof(struct p9_trans_fd), GFP_KERNEL);
799 if (!p) 800 if (!p)
800 return -ENOMEM; 801 return -ENOMEM;
801 802
802 csocket->sk->sk_allocation = GFP_NOIO; 803 csocket->sk->sk_allocation = GFP_NOIO;
803 fd = sock_map_fd(csocket, 0); 804 file = sock_alloc_file(csocket, 0);
804 if (fd < 0) { 805 if (IS_ERR(file)) {
805 pr_err("%s (%d): failed to map fd\n", 806 pr_err("%s (%d): failed to map fd\n",
806 __func__, task_pid_nr(current)); 807 __func__, task_pid_nr(current));
807 sock_release(csocket); 808 sock_release(csocket);
808 kfree(p); 809 kfree(p);
809 return fd; 810 return PTR_ERR(file);
810 } 811 }
811 812
812 get_file(csocket->file); 813 get_file(file);
813 get_file(csocket->file); 814 p->wr = p->rd = file;
814 p->wr = p->rd = csocket->file;
815 client->trans = p; 815 client->trans = p;
816 client->status = Connected; 816 client->status = Connected;
817 817
818 sys_close(fd); /* still racy */
819
820 p->rd->f_flags |= O_NONBLOCK; 818 p->rd->f_flags |= O_NONBLOCK;
821 819
822 p->conn = p9_conn_create(client); 820 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 @@
70#include <linux/init.h> 70#include <linux/init.h>
71#include <linux/crypto.h> 71#include <linux/crypto.h>
72#include <linux/slab.h> 72#include <linux/slab.h>
73#include <linux/file.h>
73 74
74#include <net/ip.h> 75#include <net/ip.h>
75#include <net/icmp.h> 76#include <net/icmp.h>
@@ -4276,6 +4277,7 @@ static int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval
4276{ 4277{
4277 sctp_peeloff_arg_t peeloff; 4278 sctp_peeloff_arg_t peeloff;
4278 struct socket *newsock; 4279 struct socket *newsock;
4280 struct file *newfile;
4279 int retval = 0; 4281 int retval = 0;
4280 4282
4281 if (len < sizeof(sctp_peeloff_arg_t)) 4283 if (len < sizeof(sctp_peeloff_arg_t))
@@ -4289,22 +4291,35 @@ static int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval
4289 goto out; 4291 goto out;
4290 4292
4291 /* Map the socket to an unused fd that can be returned to the user. */ 4293 /* Map the socket to an unused fd that can be returned to the user. */
4292 retval = sock_map_fd(newsock, 0); 4294 retval = get_unused_fd();
4293 if (retval < 0) { 4295 if (retval < 0) {
4294 sock_release(newsock); 4296 sock_release(newsock);
4295 goto out; 4297 goto out;
4296 } 4298 }
4297 4299
4300 newfile = sock_alloc_file(newsock, 0);
4301 if (unlikely(IS_ERR(newfile))) {
4302 put_unused_fd(retval);
4303 sock_release(newsock);
4304 return PTR_ERR(newfile);
4305 }
4306
4298 SCTP_DEBUG_PRINTK("%s: sk: %p newsk: %p sd: %d\n", 4307 SCTP_DEBUG_PRINTK("%s: sk: %p newsk: %p sd: %d\n",
4299 __func__, sk, newsock->sk, retval); 4308 __func__, sk, newsock->sk, retval);
4300 4309
4301 /* Return the fd mapped to the new socket. */ 4310 /* Return the fd mapped to the new socket. */
4311 if (put_user(len, optlen)) {
4312 fput(newfile);
4313 put_unused_fd(retval);
4314 return -EFAULT;
4315 }
4302 peeloff.sd = retval; 4316 peeloff.sd = retval;
4303 if (put_user(len, optlen)) 4317 if (copy_to_user(optval, &peeloff, len)) {
4318 fput(newfile);
4319 put_unused_fd(retval);
4304 return -EFAULT; 4320 return -EFAULT;
4305 if (copy_to_user(optval, &peeloff, len)) 4321 }
4306 retval = -EFAULT; 4322 fd_install(retval, newfile);
4307
4308out: 4323out:
4309 return retval; 4324 return retval;
4310} 4325}
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 = {
346 * but we take care of internal coherence yet. 346 * but we take care of internal coherence yet.
347 */ 347 */
348 348
349static struct file *sock_alloc_file(struct socket *sock, int flags) 349struct file *sock_alloc_file(struct socket *sock, int flags)
350{ 350{
351 struct qstr name = { .name = "" }; 351 struct qstr name = { .name = "" };
352 struct path path; 352 struct path path;
@@ -375,8 +375,9 @@ static struct file *sock_alloc_file(struct socket *sock, int flags)
375 file->private_data = sock; 375 file->private_data = sock;
376 return file; 376 return file;
377} 377}
378EXPORT_SYMBOL(sock_alloc_file);
378 379
379int sock_map_fd(struct socket *sock, int flags) 380static int sock_map_fd(struct socket *sock, int flags)
380{ 381{
381 struct file *newfile; 382 struct file *newfile;
382 int fd = get_unused_fd_flags(flags); 383 int fd = get_unused_fd_flags(flags);
@@ -392,7 +393,6 @@ int sock_map_fd(struct socket *sock, int flags)
392 put_unused_fd(fd); 393 put_unused_fd(fd);
393 return PTR_ERR(newfile); 394 return PTR_ERR(newfile);
394} 395}
395EXPORT_SYMBOL(sock_map_fd);
396 396
397struct socket *sock_from_file(struct file *file, int *err) 397struct socket *sock_from_file(struct file *file, int *err)
398{ 398{