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 /net/sctp/socket.c | |
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>
Diffstat (limited to 'net/sctp/socket.c')
-rw-r--r-- | net/sctp/socket.c | 25 |
1 files changed, 20 insertions, 5 deletions
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 | } |