diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2012-08-18 00:25:51 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2012-09-26 21:08:50 -0400 |
commit | 56b31d1c9f1e6a3ad92e7bfe252721e05d92b285 (patch) | |
tree | 44521dbcdf51695b6092f2a4dabe83f460c2ed7c | |
parent | 28407630513b1a86133db0ef8b39fabad6c494af (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.h | 3 | ||||
-rw-r--r-- | net/9p/trans_fd.c | 16 | ||||
-rw-r--r-- | net/sctp/socket.c | 25 | ||||
-rw-r--r-- | net/socket.c | 6 |
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 { | |||
65 | struct poll_table_struct; | 65 | struct poll_table_struct; |
66 | struct pipe_inode_info; | 66 | struct pipe_inode_info; |
67 | struct inode; | 67 | struct inode; |
68 | struct file; | ||
68 | struct net; | 69 | struct 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); |
247 | extern int sock_recvmsg(struct socket *sock, struct msghdr *msg, | 248 | extern int sock_recvmsg(struct socket *sock, struct msghdr *msg, |
248 | size_t size, int flags); | 249 | size_t size, int flags); |
249 | extern int sock_map_fd(struct socket *sock, int flags); | 250 | extern struct file *sock_alloc_file(struct socket *sock, int flags); |
250 | extern struct socket *sockfd_lookup(int fd, int *err); | 251 | extern struct socket *sockfd_lookup(int fd, int *err); |
251 | extern struct socket *sock_from_file(struct file *file, int *err); | 252 | extern 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) | |||
793 | static int p9_socket_open(struct p9_client *client, struct socket *csocket) | 793 | static 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 | |||
4308 | out: | 4323 | out: |
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 | ||
349 | static struct file *sock_alloc_file(struct socket *sock, int flags) | 349 | struct 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 | } |
378 | EXPORT_SYMBOL(sock_alloc_file); | ||
378 | 379 | ||
379 | int sock_map_fd(struct socket *sock, int flags) | 380 | static 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 | } |
395 | EXPORT_SYMBOL(sock_map_fd); | ||
396 | 396 | ||
397 | struct socket *sock_from_file(struct file *file, int *err) | 397 | struct socket *sock_from_file(struct file *file, int *err) |
398 | { | 398 | { |